- 事件分发可以让我们解决一些自定义view和控制一些组件的冲突
- 用了一个设计模式:责任链设计模式
0x02 事件分发
1: 先上个图片
2: 根据图片进行分析
事件分发最开始是通过activity的 dispatchTouchEvent 方法来进行的,activity上一层是C/C++层,具体应该是跟屏幕驱动之类的了。
根据代码:
父控件的dispatchTouchEvent返回true,父控件自己的拦截也走了,事件直接在dispatchTouchEvent的地方消耗了
dispatchTouchEvent(view中的方法被ViewGroup重写) | onTouchEvent(View中的被ViewGroup重写,onClickListener在它的UP事件上面) | onInterceptTouchEvent(只有ViewGroup中有) | |
---|---|---|---|
父控件(ViewGroup) | 其实只要不调用父类的方法(super.dispatchTouchEvent(ev))都在dispatchTouchEvent这里就不往下面传递了,这里最好根据上滑动或者下滑动的方式,或者是MOVE,DOWN,UP事件来进行判断,如:自己需要上滑动的情况下来进行返回true不给子控件点击这种来进行,相当于单个来进行放回true,尽量不要直接返回true来进行全部自己消费。 |
这个是事件的最终消费的方法.这里分两种情况:1.就是onInterceptTouchEvent不返回true的情况下。只要用户的点击不命中自己的上面(就是点击没有在自己的区域上面,源码的dispatchTouchEvent里面判断完整的点击事件在UP事件上面,并进行了点击范围的处理),都不会调用这个方法,即使命中的控件是enable是false的 2.就是onInterceptTouchEvent返回true,表示拦截了子类的某种行为。这个方法就会被回调 |
如果返回true的话就会直接不给自己的子View点击事件了 |
子控件(view,不是viewGroup) | 如果直接返回true,自己的onTouchEvent不会执行。viewGroup也一样(onInterceptTouchEvent也不执行了,因为onInterceptTouchEvent来进行是否分发在它的dispatchTouchEvent中) | 如果返回true就代表事件在这里就消耗了。 | view中没有该方法 |
requestDisallowInterceptTouchEvent说明,一开始拦截了就不起效果了:
第一个事件是先调用 ViewGroup 的 onIntercept 的,所以如果一开始 ViewGroup 就打算拦截,子 View 将没有任何机会;
所有的事件以:ACTION_DOWN 开始,ACTION_UP 或者 ACTION_CANCEL 结束
3:解决冲突从父组件的onInterceptTouchEvent入手
1 |
|
如果不允许子控件滑动,就直接禁止这种方式,防止父类不能进行滑动。
只不过,还有很多种情况,比如,子控件可以滑动,通过滑动到第一个item或者说不能滑动的时候,然后又把滚动的权利还给父控件,然后就连贯了
getFirstVisiblePosition / getLastVisiblePosition 或者canScrollVertically(-1) 这些方式来判断滑动是否到了极限值,然后给另一个需要滑动的控件来进行滑动