关于解决多个viewpager嵌套所遇到的事件传递问题
2016-03-25 23:56
232 查看
在开发时候我们会有一种情景,类似于新闻客户端的,就是在主页面的viewpager里面的view或者frament中再嵌套了一个viewpager,这时候如果不做任何处理的话,我们父view中的viewpager和子view的viewpager会产生冲突,比如滑动的卡顿等。
所以为了解决这个情况我们需要了解一下安卓中的事件传递机制。如果有对安卓的事件传递机制的人不那么熟悉的话,那请自己去研究一下,在这里我只简单说一下时间传递机制的基本原理。
说明:
首先触摸事件发生时(ACTION_DOWN),由系统调用Activity的dispatchTouchEvent方法,分发该事件。根据触摸事件的坐标,将此事件传递给out的dispatchTouchEvent处理,out则调用onInterceptTouchEvent 判断事件是由自己处理,还是继续分发给子View。此处由于out不处理Touch事件,故根据事件发生坐标,将事件传递给out的直接子View(即middle)。
Middle及Center中事件处理过程同上。但是由于Center组件是clickable 表示其能处理Touch事件,故center中的onInterceptTouchEvent方法将事件传递给center自己的onTouchEvent方法处理。至此,此Touch事件已被处理,不继续进行传递。
关于事件传递自己有以下总结
1. 事件首先传递给父控件-->父控件最新接收到事件,`拥有事件处理的最高优先级`;2. 关键方法
1. dispatchTouchEvent:是否派发,常见处理-->不做任何的处理.
2. onInterceptTouchEvent:是否拦截
1. 是(true)-->调用自己的onTouchEvent去处理事件,`如果你对MotionEvent进行了拆分(action_down,action_move,action_up,action_cancel),这个时候传递流程不能说的那么绝对`
2. 否(false)-->事件传递给孩子
1. 孩子是view-->ontouchEvent
2. 孩子是viewGroup-->和之前的情况一样
3. onTouchEvent:是否消费
1. return true:消费事件
2. return false:不消费事件
以下是在自己写的程序中打印的一些测试log
ScrollableViewGroup以及ViewHook事件传递流程分析---ScrollableViewGroup(父亲)----onInterceptTouchEvent---MotionEvent.ACTION_DOWN--- return false
---viewGroudHook---onTouchEvent---ACTION_DOWN return true
----ScrollableViewGroup(父亲)---onInterceptTouchEvent---MotionEvent.ACTION_MOVE--- return true,onInterceptTouchEvent返回true的时候.肯定回来自己的onTouchevent里面,但是可能会去孩子那里执行以下action_cancel
---viewGroudHook---onTouchEvent---ACTION_CANCEL--->这个地方很容易产生疑惑
---ScrollableViewGroup(父亲)---onTouchEvent-----MotionEvent.ACTION_MOVE------- 父亲在onInterceptTouchEvent里面的action_move分支下return true,所以我们进入的是ontouchEvent的Action_move
---ScrollableViewGroup(父亲)---onTouchEvent-----MotionEvent.ACTION_MOVE------- 这里我们用打断点的形式.没有看到action_move.所以我们常用打日志的形式进行了分析
---ScrollableViewGroup(父亲)---onTouchEvent-----MotionEvent.ACTION_MOVE-------
---ScrollableViewGroup(父亲)---onTouchEvent-----MotionEvent.ACTION_UP-------
以上就是个人对安卓的事件传递机制的一些小总结,可能也借鉴了一下别人的图,请见谅
大家看了上面事件传递机制,应该也基本有所了解,所以我就直接贴源码好了。
这里我重写了viewpager,实现的逻辑是当滑动到子view的viewpager的头或者尾的时候就请求父控件进行事件拦截,然后实现父view的viewpager的滑动事件。但是我看了网易新闻的客户端,貌似头条新闻并不是到尾它就切换到父viewpaer的下一个view,所以大家根据自己的需求改一下以下的代码吧
/** * 头条新闻水平滑动的ViewPager * @auth a62c or Administrator * */ public class TopNewsViewPager extends ViewPager{ private int startX; private int startY; public TopNewsViewPager(Context context) { super(context); // TODO Auto-generated constructor stub } public TopNewsViewPager(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } /** * 事件分发,请求父控件及祖宗控件是否拦截事件 * 1.用户右滑,而且是第一个页面,就需要父控件拦截,显示上一个标签或者侧边栏 * 2.用户左滑,而且是最后一个页面,就需要父控件拦截,显示下一个标签 * 3.上下滑动,需要父控件拦截 */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { // //用getParent去请求,希望父控件不拦截这个OnToch事件 // getParent().requestDisallowInterceptTouchEvent(true); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //用getParent去请求,希望父控件不拦截这个OnToch事件 //这样为了保证ACTION_MOVE调用 getParent().requestDisallowInterceptTouchEvent(true); startX = (int) ev.getRawX(); startY = (int) ev.getRawY(); break; case MotionEvent.ACTION_MOVE: int endX=(int) ev.getRawX(); int endY=(int) ev.getRawY(); if(Math.abs(endX-startX)>Math.abs(endY-startY)){//左右滑动 if(endX>startX){//右滑 if(getCurrentItem()==0){//第一个页面,需要父控件拦截 getParent().requestDisallowInterceptTouchEvent(false); } }else{//左滑 if(getCurrentItem()==getAdapter().getCount()-1){//最后一个页面,需要拦截 getParent().requestDisallowInterceptTouchEvent(false); } } }else{//上下滑动,需要父控件拦截 getParent().requestDisallowInterceptTouchEvent(false); } break; } return super.dispatchTouchEvent(ev); } }
以上大概就是我对多个viewpager嵌套的事件传递的解决吧。
相关文章推荐
- 大数据可视化工具Hue安装使用
- POJ 2945 trie树
- OkHttp execute方法和enqueue方法的区别
- POJ 2945 trie树
- IOS-TextField知多少
- 04-树5 Root of AVL Tree
- 在ubunt14.04(linux)下利用cmake编译运行opencv程序
- Oracle中 无法删除当前已经连接的用户 解决方法
- Nginx学习笔记——提供静态内容
- iOS高级控件之TableView(一)城市信息(1)
- Android实现一键获取课程成绩dome
- IOS开发UI篇—懒加载
- 3-4 rpm包查询
- 热补丁介绍及Andfix的使用
- 第一篇博客
- php ci 获取表单中多个同名input元素值的代码
- 找出数组中出现次数超过数组长度一半的元素—-腾讯
- com.sun.tools.javac.code.Symbol$CompletionFailure: 找不到java.lang.invoke.MethodType的类文件
- 各浏览器下字体问题记录
- HDU:2277 Change the ball(水)(数学)