Andoird自定义ViewGroup实现竖向引导界面

一般进入APP都有欢迎界面,基本都是水平滚动的,今天和大家分享一个垂直滚动的例子。
先来看看效果把:

首先是布局文件:

<com.example.verticallinearlayout.VerticalLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:tools="http://schemas.android.com/tools"  android:id="@+id/id_main_ly"  android:layout_width="match_parent"  android:layout_height="fill_parent"  android:orientation="vertical"  android:background="#fff" >  <RelativeLayout  android:layout_width="fill_parent"  android:layout_height="fill_parent"  android:background="@drawable/w02" >  <Button  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:text="hello" />  </RelativeLayout>  <RelativeLayout  android:layout_width="fill_parent"  android:layout_height="fill_parent"  android:background="@drawable/w03" >  <Button  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:layout_centerInParent="true"  android:background="#fff"  android:text="hello" />  </RelativeLayout>  <RelativeLayout  android:layout_width="fill_parent"  android:layout_height="fill_parent"  android:background="@drawable/w04" >  <Button  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:layout_centerInParent="true"  android:text="hello" />  </RelativeLayout>  <RelativeLayout  android:layout_width="fill_parent"  android:layout_height="fill_parent"  android:background="@drawable/w05" >  <Button  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:layout_centerInParent="true"  android:text="hello" />  </RelativeLayout>  </com.example.verticallinearlayout.VerticalLinearLayout>  

自定义的Layout了

package com.example.verticallinearlayout;import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Scroller;public class VerticalLinearLayout extends ViewGroup
{/*** 屏幕的高度*/private int mScreenHeight;/*** 手指按下时的getScrollY*/private int mScrollStart;/*** 手指抬起时的getScrollY*/private int mScrollEnd;/*** 记录移动时的Y*/private int mLastY;/*** 滚动的辅助类*/private Scroller mScroller;/*** 是否正在滚动*/private boolean isScrolling;/*** 加速度检测*/private VelocityTracker mVelocityTracker;/*** 记录当前页*/private int currentPage = 0;private OnPageChangeListener mOnPageChangeListener;public VerticalLinearLayout(Context context, AttributeSet attrs){super(context, attrs);/*** 获得屏幕的高度*/WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);mScreenHeight = outMetrics.heightPixels;// 初始化mScroller = new Scroller(context);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);int count = getChildCount();for (int i = 0; i < count; ++i){View childView = getChildAt(i);measureChild(childView, widthMeasureSpec, heightMeasureSpec);}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b){if (changed){int childCount = getChildCount();// 设置主布局的高度MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();lp.height = mScreenHeight * childCount;setLayoutParams(lp);for (int i = 0; i < childCount; i++){View child = getChildAt(i);if (child.getVisibility() != View.GONE){child.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);// 调用每个自布局的layout}}}}@Overridepublic boolean onTouchEvent(MotionEvent event){// 如果当前正在滚动,调用父类的onTouchEventif (isScrolling)return super.onTouchEvent(event);int action = event.getAction();int y = (int) event.getY();obtainVelocity(event);switch (action){case MotionEvent.ACTION_DOWN:mScrollStart = getScrollY();mLastY = y;break;case MotionEvent.ACTION_MOVE:if (!mScroller.isFinished()){mScroller.abortAnimation();}int dy = mLastY - y;// 边界值检查int scrollY = getScrollY();// 已经到达顶端,下拉多少,就往上滚动多少if (dy < 0 && scrollY + dy < 0){dy = -scrollY;Log.i("test", "已经到达顶端,下拉多少,就往上滚动多少scrollY="+scrollY);}// 已经到达底部,上拉多少,就往下滚动多少if (dy > 0 && scrollY + dy > getHeight() - mScreenHeight){dy = getHeight() - mScreenHeight - scrollY;Log.i("test", "已经到达顶端,下拉多少,就往上滚动多少scrollY=="+scrollY);}Log.i("test", "dy="+dy+",scrollY"+scrollY);scrollBy(0, dy);mLastY = y;break;case MotionEvent.ACTION_UP:mScrollEnd = getScrollY();int dScrollY = mScrollEnd - mScrollStart;if (wantScrollToNext())// 往上滑动{if (shouldScrollToNext()){mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - dScrollY);} else{mScroller.startScroll(0, getScrollY(), 0, -dScrollY);}}if (wantScrollToPre())// 往下滑动{if (shouldScrollToPre()){mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight - dScrollY);} else{mScroller.startScroll(0, getScrollY(), 0, -dScrollY);}}isScrolling = true;postInvalidate();recycleVelocity();break;}return true;}/*** 根据滚动距离判断是否能够滚动到下一页* * @return*/private boolean shouldScrollToNext(){return mScrollEnd - mScrollStart > mScreenHeight / 2 || Math.abs(getVelocity()) > 600;}/*** 根据用户滑动,判断用户的意图是否是滚动到下一页* * @return*/private boolean wantScrollToNext(){return mScrollEnd > mScrollStart;}/*** 根据滚动距离判断是否能够滚动到上一页* * @return*/private boolean shouldScrollToPre(){return -mScrollEnd + mScrollStart > mScreenHeight / 2 || Math.abs(getVelocity()) > 600;}/*** 根据用户滑动,判断用户的意图是否是滚动到上一页* * @return*/private boolean wantScrollToPre(){return mScrollEnd < mScrollStart;}@Overridepublic void computeScroll(){super.computeScroll();if (mScroller.computeScrollOffset()){scrollTo(0, mScroller.getCurrY());postInvalidate();} else{int position = getScrollY() / mScreenHeight;Log.e("xxx", position + "," + currentPage);if (position != currentPage){if (mOnPageChangeListener != null){currentPage = position;mOnPageChangeListener.onPageChange(currentPage);}}isScrolling = false;}}/*** 获取y方向的加速度* * @return*/private int getVelocity(){mVelocityTracker.computeCurrentVelocity(1000);return (int) mVelocityTracker.getYVelocity();}/*** 释放资源*/private void recycleVelocity(){if (mVelocityTracker != null){mVelocityTracker.recycle();mVelocityTracker = null;}}/*** 初始化加速度检测器* * @param event*/private void obtainVelocity(MotionEvent event){if (mVelocityTracker == null){mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.addMovement(event);}/*** 设置回调接口* * @param onPageChangeListener*/public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener){mOnPageChangeListener = onPageChangeListener;}/*** 回调接口* * @author zhy* */public interface OnPageChangeListener{void onPageChange(int currentPage);}
}

释还是相当详细的,我简单描述一下,Action_down时获得当前的scrollY,然后Action_move时,根据移动的距离不断scrollby就行了,当前处理了一下边界判断,在Action_up中再次获得scrollY,两个的scrollY进行对比,然后根据移动的距离与方向决定最后的动作

MainActivity

package com.example.verticallinearlayout;import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;import com.example.verticallinearlayout.VerticalLinearLayout.OnPageChangeListener;public class MainActivity extends Activity
{private VerticalLinearLayout mMianLayout;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mMianLayout = (VerticalLinearLayout) findViewById(R.id.id_main_ly);mMianLayout.setOnPageChangeListener(new OnPageChangeListener(){@Overridepublic void onPageChange(int currentPage){
//              mMianLayout.getChildAt(currentPage);Toast.makeText(MainActivity.this, "第"+(currentPage+1)+"页", Toast.LENGTH_SHORT).show();}});}}

为了提供可扩展性,还是定义了回调接口,完全可以把这个当成一个垂直的ViewPager使用。
总结下:
Scroller这个辅助类还是相当好用的,原理我简单说一下:每次滚动时,让Scroller进行滚动,然后调用postInvalidate方法,这个方法会引发调用onDraw方法,onDraw方法中会去调用computeScroll方法,然后我们在computScroll中判断,Scroller的滚动是否结束,没有的话,把当前的View滚动到现在Scroller的位置,然后继续调用postInvalidate,这样一个循环的过程。
画张图方便大家理解,ps:没找到什么好的画图工具,那rose随便画了,莫计较。

源码

源码点击此处下载

完成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/494136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

科技|全球首款飞行汽车开始量产!下月开始预售,2023年后或可实现一键打“飞车”...

来源&#xff1a; 世界科技创新论坛飞机与汽车结合的产物真的要来了。在2018全球未来出行大会上&#xff0c;吉利副总裁杨学良透露&#xff0c;由吉利控股的全资子公司、全球首家飞行汽车公司美国太力飞行汽车公司推出的“全球首款量产飞行汽车”——Transition&#xff0c;将于…

Android手势锁实现

最终效果如下 整体思路 a、自定义了一个RelativeLayout(GestureLockViewGroup)在里面会根据传入的每行的个数&#xff0c;生成多个GestureLockView&#xff08;就是上面一个个小圈圈&#xff09;&#xff0c;然后会自动进行布局&#xff0c;里面的宽度&#xff0c;间距&#x…

智能连接:5G与人工智能、物联网等技术的超级融合

来源&#xff1a;资本实验室随着新技术的成熟&#xff0c;新型的、先进的应用将来自5G、人工智能&#xff08;AI&#xff09;和物联网&#xff08;IoT&#xff09;的融合。这种融合将创造出一个智能连接的世界&#xff0c;对所有个人、行业、社会和经济产生积极影响。从现在到2…

一个绚丽的loading动效分析与实现!

最终效果如下 从效果上看&#xff0c;我们需要考虑以下几个问题&#xff1a; 1.叶子的随机产生&#xff1b; 2.叶子随着一条正余弦曲线移动&#xff1b; 3.叶子在移动的时候旋转&#xff0c;旋转方向随机&#xff0c;正时针或逆时针&#xff1b; 4.叶子遇到进度条&#xff…

20岁的谷歌,和它“最成功”的大败笔

来源&#xff1a;大数据文摘编译&#xff1a;张驰、JIN、涂世文、钱天培谷歌20岁了&#xff01;20年中&#xff0c;谷歌打造了无数或成功或流产的产品&#xff0c;其中&#xff0c;这一名为“谷歌光纤”计划的失败或许是它最“成功”的“大败笔”。2010年&#xff0c;谷歌宣布了…

自定义viewgroup实现ArcMenu

最终效果如下 实现思路 通过效果图&#xff0c;会有几个问题&#xff1a; a、动画效果如何实现 可以看出动画是从顶点外外发射的&#xff0c;可能有人说&#xff0c;那还不简单&#xff0c;默认元素都在定点位置&#xff0c;然后TraslateAnimation就好了&#xff1b;这样忽略…

也谈谈Atiyah关于黎曼猜想的证明

来源&#xff1a;潇轩社作者&#xff1a;叶扬波 著名数学家&#xff0c;美国爱荷华大学教授。作为数论学家&#xff0c;他在中国大陆出版有《迹公式与模形式》等专著。以下是他谈Atiyah关于黎曼猜想的证明的文章&#xff0c;观点专业而且独到&#xff0c;转载此文&#xff0c;…

大型Javascript应用架构的模式(译文)

附上翻译好的word文件 http://files.cnblogs.com/lizhug/Patterns_For_Large-Scale_JavaScript_Application_Architecture.zip 作者&#xff1a;Addy Osmani 技术评审&#xff1a;Andree Hansson 翻译&#xff1a;李珠刚 珠刚参上 今天我们将要探讨一系列用于大型Javascri…

Animation Property Animation 使用

本篇主要讲Animation 和 Property Animation的使用&#xff0c;最后会讲QQ管家桌面火箭作为例子&#xff1a; 在Android中开发动效有两套框架可以使用&#xff0c;分别为 Animation 和 Property Animation&#xff1b; 相对来说&#xff0c;Animator比Animation要强大太多&…

华为云力推“普惠AI”,EI智能体正在落地行业

来源&#xff1a;北京物联网智能技术应用协会云计算和人工智能是什么关系&#xff1f;一般认为&#xff0c;云计算是人工智能的基础之一。而华为云则认为&#xff0c;要推动人工智能的落地&#xff0c;拥有“算法、算力和数据”还是不足够的&#xff0c;还需要“行业智慧”&…

Android中mesure过程详解

我们在编写layout的xml文件时会碰到layout_width和layout_height两个属性&#xff0c;对于这两个属性我们有三种选择&#xff1a;赋值成具体的数值&#xff0c;match_parent或者wrap_content&#xff0c;而measure过程就是用来处理match_parent或者wrap_content&#xff0c;假如…

黑科技揭秘 | 阿里云“天空物联网”连接范围如何达到700平方公里

来源&#xff1a;阿里云还记得前不久在2018杭州云栖大会上&#xff0c;由飞在天上的飞艇、地下基站共同搭建的阿里云“天空物联网”吗&#xff1f;它实现从地面40000米高空到地下20米的覆盖&#xff0c;并持续为大会服务。体现了持续加码的阿里巴巴物联网战略。在飞艇背后&…

JAVA-用栈机制实现单词逆序排列

就是IO那一段还没学到。 之前的PUCH,POP,STRING和CHAR的关系搞得懂了。 学到一个定位STRING当中CHAR的转换函数。 char String.charAt(x) 1 import java.io.*;2 3 4 class stackString5 {6 private int maxSize;7 private char[] stackX;8 private int top;9 …

Android自定义实现FlowLayout

实现FlowLayout 何为FlowLayout&#xff0c;如果对Java的Swing比较熟悉的话一定不会陌生&#xff0c;就是控件根据ViewGroup的宽&#xff0c;自动的往右添加&#xff0c;如果当前行剩余空间不足&#xff0c;则自动添加到下一行。有点所有的控件都往左飘的感觉&#xff0c;第一…

【重磅】马斯克遇终极麻烦:被起诉欺诈罪 或丢掉CEO职位 特斯拉暴跌约13%

参考&#xff1a;CNBC、Bloomberg编译&#xff1a;网易智能编辑&#xff1a;丁广胜参与&#xff1a;小小美国当地时间周四&#xff0c;法庭的文件显示特斯拉电动汽车公司首席执行官伊隆马斯克(Elon Musk)已被美国证券交易委员会(SEC)以欺诈罪起诉。与特斯拉关系密切的消息人士透…

《麻省理工科技评论》:2018年18大科技趋势,2017年7大失败技术

来源&#xff1a;科技周摘要&#xff1a;2018 年伊始&#xff0c;许多科技大势仍在继续&#xff0c;正如比尔盖茨所说&#xff0c;“大多数人高估了某种技术的短期价值&#xff0c;低估了其长期价值。”同样&#xff0c;大多数的年度预测会高估了一年内一些事件发生的可能性&am…

Android实现支持缩放平移图片

本文主要用到了以下知识点 MatrixGestureDetector 能够捕捉到长按、双击ScaleGestureDetector 用于检测缩放的手势 自由的缩放 需求&#xff1a;当图片加载时&#xff0c;将图片在屏幕中居中&#xff1b;图片宽或高大于屏幕的&#xff0c;缩小至屏幕大小&#xff1b;自由对图…

放麦子

题意&#xff1a; 国际象棋&#xff0c;一共64个方格&#xff0c;第一个格子里放一粒麦子&#xff0c;第二个放2粒&#xff0c;第三个放4粒&#xff0c;第四个放8粒。。。。。&#xff08;后面的数字是前面的两倍&#xff09; 求放满64个格子&#xff0c;一共需要多少粒麦子。 …

Material Design风格登录注册

本文实现了以下功能 完整的代码和样例托管在Github当接口锁定时&#xff0c;防止后退按钮显示在登录Activity 上。自定义 ProgressDialog来显示加载的状态。符合材料设计规范。悬浮标签&#xff08;floating labels&#xff09;&#xff08;来自设计支持库&#xff09;用户表单…

英特尔反驳质疑:芯片供应充足、10nm量产没问题

来源&#xff1a;华尔街见闻摘要&#xff1a;英特尔称2018年会将资本支出增加10亿美元&#xff0c;至总额创纪录的150亿美元&#xff1b;CEO称&#xff0c;个人电脑需求意外回升&#xff0c;但有足够供应满足市场&#xff0c;有望达成全年营收目标&#xff0c;股价涨近4%。竞争…