为了账号安全,请及时绑定邮箱和手机立即绑定

View事件分发机制

标签:
Android

!通过阅读Android开发艺术探索整理

重要方法:

dispatchTouchEvent

onInterceptTouchEvent

onTouchEvent

三者关系:dispatchTouchEvent{ if(onInterceptTouchEvent) return onTouchEvent; else return child.dispatchTouchEvent; }

规则:对根ViewGroup,产生点击事件时,dispatchTouchEvent就会调用,如果onInterceptTouchEvent返回true拦截,将事件交给自身的onTouchEvent,反之,传递到子元素,子元素dispatchTouchEvent调用,如此反复直到事件最终被处理。

优先级:onTouchLinstener>onTouchEvent>onClickLinstener;onTouch返回false,onTouchEvent调用;

事件传递顺序:Activity、Window、顶级View

特殊情况:onTouchEvent返回false,事件将传递给父类容器,以此类推,若所有元素都不处理,最终事件传递到Activity,由Activity的onTouchEvent处理

一些结论:

1.事件序列以down开始,数量不定的move,以up事件结束

2.某个View一旦决定拦截,一个事件序列都只能由它来处理,不会再询问onInterceptTouchEvent是否拦截

3.正常情况下,一个事件序列只能由一个View拦截消耗,通过特殊手段可以将本View该处理的onTouchEvent强行传递给其他View

4.某个View一旦开始处理事件,如果不消耗down事件,那么同一事件序列中的其他事件不会再交给该View,将事件重新交给父元素处理,调用onTouchEvent。事件一旦交给一个View处理,必须消耗掉,否则剩下的事件不再交给它

5.如果一个View不消耗除down事件以外的其他事件,那么事件会消失,父元素onTouchEvent不会被调用,可以接收后续事件。最终消失的点击事件会传递给Activity处理。

6.View 没有onInterceptTouchEvent方法,一旦接收到事件传递,onTouchEvent必然会被调用。

7.ViewGroup默认不拦截任何事件,源码中ViewGroup的onInterceptTouch事件默认返回false

8.View的onTouchEvent默认都会消耗事件,返回true.除非不可点击,clickable及longClickable同时为false。默认longClickable都为false,Button的clickable为true,TextView的为false

9.View的enable属性不影响onTouchEvent默认返回值

10.onClick会发生的前提是当前View可点击,并且接收到down和up事件

11.事件传递过程由外向内,总是先交给夫元素,再由父元素分发给子元素,通过requestDisallowInterceptTouchEvent可以在子元素中干预父元素的事件分发过程,down事件除外。

Activity传递到Window,也就是phoneWindow,由phoneWindow传递到顶层View,既decorView,setContView的父View,最终一定会传递到View。

顶层View处理传递流程:

事件到达顶层View,dispatchTouchEvent会调用,如果拦截,返回true,则由ViewGroup的TouchEvent处理,此时如果设置了onTouchLinstener,会调用onTouch,屏蔽掉onToucheEvent,在onTouchEvent中如果设置了onClickLinstener,会调用onClick,如果顶层View不拦截,则事件会传递到它所在的点击事件链上的子View,子View的dispatchTouchEvent会调用。至此,事件已经从顶层传递到了子View,接下来传递过程跟顶层View一直,如此循环,直到事件被处理

滑动冲突:

常见的几种场景:

1.外部滑动方向与内部不一致

2.外部滑动方法与内部一致

3.上面两种情况的嵌套

处理规则:

1.左右滑动时,由外部View拦截,上下滑动时由内部View拦截。通常可根据滑动距离差判断是水平滑动还是上下滑动,也可以滑动路径与水平方向的夹角,特殊的可以用水平与竖直方向的速度差

2.业务制定:如处于某种状态时需要外部相应滑动,另一种状态时内部相应滑动

3.业务突破点

解决方案:

1.外部拦截法

点击事件都先经过父容器拦截处理,如果父容器需要此事件就拦截,不需要就不拦截。

典型逻辑:重写父容器onInterceptTouchEvent: down必须返回false,不拦截,否则后续事件都要由父元素处理,此时事件无法传递到子元素,up返回false因为该事件本事意义不大,move事件根据是否需要当前点击事件决定是否拦截

2.内部拦截法

父容器不拦截任何事件,所有事件都传递到子元素,如果子元素需要就消耗掉,不需要就交父容器处理,需要配合requestDisallowInterceptTouchEvent。

典型逻辑:重写子元素的dispatchTouchEvent,down事件parent.requestDisallowInterceptTouchEvent(true),move事件,当父容器需要此类点击事件时,parent.requestDisallowInterceptTouchEvent(true)。除子元素处理外,父元素也需要默认拦截除down事件外的其他事件。

down事件不受FLAG_DISSALOW_INTERCEPT标记位控制,一旦父元素拦截down事件,那么所有的事件都无法传递到子元素,内部拦截将无效

原文链接:http://www.apkbus.com/blog-35555-69418.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消