参考网址:Android艺术开发探索第三章————View的事件体系(下)
一.View的事件分发
1.点击事件的传递规则
dispatchTouchEvent
用来进行事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件。
onInterceptTouchEvent
在上述方法内部调用,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件
onTouchEvent
在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View无法再次接收到事件。
OnTouchListener比onTouchEvent的优先级高,OnClickListener的优先级最低。
OnClickListener < onTouchEvent <OnTouchListener
当一个点击事件产生后,它的传递过程遵循如下顺序:Activity>Window-View,即事件总是先传递给Activity,Activity再传递给Window,最后Window再传递给顶级View顶级View接收到事件后,就会按照事件分发机制去分发事件
考虑一种情况,如果一个view的onTouchEvent返回false,那么它的父容器的onTouchEvent将会被调用,依此类推,如果所有的元素都不处理这个事件,那么这个事件将会最终传递给Activity处理,即Activity的onTouchEvent方法会被调用
ViewGroup默认不拦截任何事件。Android源码中ViewGroup的onInterceptTouchEvent方法默认返回false
View没有onInterceptTouchEvent方法,一旦有点击事件传递给它,那么它的onTouchEvent方法就会被调用。
view 的enable.属性不影响onTouchEvent的默认返回值。哪怕一个View是disable状态的,只要它的clickable或者longclickable有一个为true,那么它的onTouchEvent就返会true。
事件传递过程是由外到内的,理解就是事件总是先传递给父元素,然后再由父元素分发给子View
2.事件分发的源码解析
1.Activity对点击事件的分发过程
当一个点击操作发生的时候,事件最先传递给Activity,由Activity的dispatchTouchEvent来进行事件的派发,具体的工作是由Activity内部的window来完成的,window会将事件传递给decor view,decor view一般都是当前界面的底层容器(setContentView所设置的父容器),通过Activity.getWindow.getDecorView()获得,
2.顶级View对事件的分发过程
二.View的滑动冲突
1.常见的滑动冲突场景
- 外部滑动方向和内部滑动方向不一致
- 外部滑动方向和内部滑动方向一致
- 上面两种情况的嵌套
2.滑动冲突的处理规则
3.滑动冲突的解决方式
1.外部拦截法
重新父容器的onInterceptTouchEvent方法
2.内部拦截法
父容器重写onInterceptTouchEvent方法,当down的时候返回false,其他都返回true即可;
子元素需要重写dispatchTouchEvent方法,和requestDisallowInterceptTouchEvent组合使用;
如果父容器在down的时候拦截事件,那后面的所有操作都会执行父容器的点击事件;