View的滑动冲突解决-android开发艺术探索笔记
来源:互联网 发布:搜狗上的动态壁纸软件 编辑:程序博客网 时间:2024/05/17 07:52
最近在准本找工作的同时,也在慢慢的看android开发艺术探索这本书感觉写的真是太好了,有空下来就做个笔记,下面进入正题:
滑动冲突的产生:
在页面中要有内外两层勇士滑动,这个时候就会产生滑动冲突了,比如scrollerView嵌套listview这种情况。
常见的冲突场景:
场景一:外部滑动方向和内部滑动方向的不一致(eq: horizontalScrollview和listview的嵌套)
场景二:外部滑动方向和内部滑动方向一致(eq: verticalScrollView和listview的嵌套)
场景三:上面两种情况的嵌套
滑动冲突的处理原则:
根据滑动时水平滑动还是竖直滑动来判断到底是由外部的view拦截触摸事件还是内部的view拦截触摸事件
如何判断水平滑动还是竖直滑动?
1.根据滑动路径和水平方向的夹角进行判断
2.根据水平方向和竖直方向的距离差进行判断
3.特殊时候可以根据水平和竖直方向的速度差来做判断
解决方式:
1.内部拦截法
2.外部拦截法
外部拦截法
指点击事情都先经过父容器的拦截处理,如果父容器需要此事件则拦截,否则下发到子控件中。外部拦截法需要重写父容器的onInterceptTouchEvent方法,做相应的拦截即可
伪代码:
父容器:
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean intercept=false; int x= (int) ev.getX(); int y= (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: intercept=false; break; case MotionEvent.ACTION_MOVE: if (父容器需要当前点击事件) { intercept=true; }else { intercept=false; } break; case MotionEvent.ACTION_UP: intercept=false; break; } return intercept; }
MotionEvent.ACTION_UP这里必须返回false,考虑一种情况,如果在父容器ACTION_UP返回了true,会导致子元素无法接受到ACTION_UP事件,那么子元素中的onClick事件就无法促发。
内部拦截法
所有事件都传递给子元素,如果子元素需要此事件则就消耗,否则交由给父容器进行处理,这种方法和android中的事件分发不一样,需要配合requestDisallowInterceptTouchEvent(boolean)进行处理,相对于外部拦截法来说,稍显复杂,我们需要重写子元素的dispatchTouchEvent():
伪代码:
子元素:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { int x= (int) ev.getX(); int y= (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: int deltaX=x-mLastX; int deltaY=x-mLastY; if (父容器需要当前点击事件) { getParent().requestDisallowInterceptTouchEvent(false); } break; } mLastX=x; mLastY=y; return super.dispatchTouchEvent(ev); }}
除了子元素需要修改以外,父容器也要默认拦截除了ACTION_DOWN以外的其他事件,这样当子元素调用getParent().requestDisallowInterceptTouchEvent(false)方法时候,父元素才能继续拦截所需的事件。
为什么父容器不能拦截ACTION_DOWN事件呢,因为ACTION_DOWN事件不受FLAG_DISALLOW_INTERCEPT这个标记位控制,所以一旦拦截了ACTION_DOWN事件,则子元素根本接收不到传递的事件,因为父容器把他拦截了。
父容器:
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action=ev.getAction(); if (action==MotionEvent.ACTION_DOWN) { return false; }else { return true; } }
这里详细讲一下requestDisallowInterceptTouchEvent(boolean)这个方法:
源码:
View源码
/** * Called when a child does not want this parent and its ancestors to * intercept touch events with * {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}. * * <p>This parent should pass this call onto its parents. This parent must obey * this request for the duration of the touch (that is, only clear the flag * after this parent has received an up or a cancel.</p> * * @param disallowIntercept True if the child does not want the parent to * intercept touch events. */ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);
我们看到里面写着,如果传入进去的值为true,说明孩子元素不想让父容器去拦截触摸事件,这是一个对外的公开方法。
我们再到Viewgroup里面查看,因为一般而言顶级View都是一个ViewGroup,我们查看Viewgroup的dispatchTouchEvent,可以在里面找到如下的源码:
// Check for interception. final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { intercepted = false; } } else { // There are no touch targets and this action is not an initial down // so this view group continues to intercept touches. intercepted = true; }/** * {@inheritDoc} */ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) { // We're already in this state, assume our ancestors are too return; } if (disallowIntercept) { mGroupFlags |= FLAG_DISALLOW_INTERCEPT; } else { mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; } // Pass it up to our parent if (mParent != null) { mParent.requestDisallowInterceptTouchEvent(disallowIntercept); } }
我们可以清楚地看到里面的逻辑:
if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { intercepted = false; }
说明这个标志确实是如我们上述形容的作用,决定父容器是否拦截触摸事件。
- View的滑动冲突解决-android开发艺术探索笔记
- Android中View的滑动冲突——Android开发艺术探索笔记
- Android开发艺术探索笔记(12)- View的滑动冲突
- Android开发艺术探索笔记(9)- View的滑动
- 读《Android开发艺术探索》---View滑动冲突
- Android中View的弹性滑动——Android开发艺术探索笔记
- Android开发艺术探索学习-View的滑动
- Android开发艺术探索笔记(10)- View的弹性滑动
- android 艺术开发探索 view移动 笔记
- Android开发艺术探索笔记(8)- View的基础
- Android 开发艺术探索笔记-View的事件分发
- 《Android开发艺术探索》笔记(View的知识体系)
- Android开发艺术探索(连载)之View的事件体系(二)View的滑动
- AnAndroid开发艺术探索读后感—View的滑动
- android View滑动冲突的解决方式
- Android开发艺术View滑动
- android View滑动冲突解决
- Android开发艺术探索笔记(15)- 自定义View
- Ext.js5的小鲱鱼分页(11)(silding pager)
- 苹果APP Store应用上架流程
- NSCondition
- java之内部类(InnerClass)----非静态内部类、静态内部类、局部内部类、匿名内部类
- hibernate设置
- View的滑动冲突解决-android开发艺术探索笔记
- 曾经的自己与现在的我
- cocoaPods 最新安装攻略
- PDA和PAD的区别何在?
- 选择手机图片上传&PHIMageManager
- netty5笔记-线程模型4-无锁队列MpscLinkedQueue
- 画图工具使用gnuplot&graphviz
- Android开发manifest.xml文件不常用属性
- 着手微信企业号的一些尝试