简介
1、View事件分发最重要的三个函数
- dispatchTouchEvent
- onInterceptTouchEvent-此方法只有ViewGroup有
- onTouchEvent
2、View层事件处理的伪代码
public boolean dispatchOnTouchEvent(MotionEvent ev){
boolean consume = false;
if(onInterceptTouchEvent(ev)){
consume = onTouchEvent(ev);
}else{
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
3、事件传递顺序(在应用层面)
Activity->PhoneWindow->DecorView
4、处理事件的优先级onTouchListener.onTouch>onTouchEvent>onClickListener
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
//先执行TouchListener的onTouch方法,若返回false则onTouchEvent不会执行
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
Tips
1)
同一个事件序列是指从ACTION_DOWN事件开始,中间包含不定的ACTION_MOVE事件,最后以ACTION_DOWN事件结束。
2)
正常情况下,一个事件序列只能由一个View 拦截且消耗,一旦拦截,同一个事件序列中的所有事件都会直接交给该View处理,不会再调用onInterceptTouchEvent(即(3))。特殊情况下,在onTouchEvent中可以将事件强行传递到其他View。
3)
当一个View决定拦截一个事件(即使在半路拦截,即拦截ACTION_MOVE,ACTION_UP会直接交给他),系统会把同一个事件序列中的剩余事件统统交给他处理,直接调用它的onTouchEvent,不会调用onInterceptTouchEvent去再询问他。
4)
一旦事件交给一个View,如果他不消耗ACTION_DOWN事件(ACTION_DOWN返回false),事件序列中剩余的事件不会交给他处理,并且将事件传递给他的父元素处理,即onTouchEvent被调用。
5)
与4)相反,如果他只消耗ACTION_DOWN(返回true),而不消耗事件序列中的其他事件,这个事件不会重新传递到父元素,而是最终交给ACTIVITY处理,
6)
ViewGroup默认不拦截事件,返回false。
7)
View没有onInterceptTouchEvent方法,一旦有事件传递给他,会直接调用它的onTouchEvent。
8)
一般View都会默认消耗事件(返回true)。除非他是不可点击的(clickable和longclickable同时为true)。
9)
View的enable属性不影响onTouchEvent返回默认值,哪怕一个view是disable的,只要他的clickable或longclickable有一个为·true,那么onTouchEvent就可以返回true。
10)
onClick会发生的前提条件是View可点击的,并且他收到了down和up事件。
11)
View事件传递是按照View树向下传递的,子View可以通过requestDisallowInterceptTouchEvent干预父元素的拦截事件的过程,除了ACTION_DOWN事件(这在解决View冲突可以派上用场)。
总结
父元素的拦截方法是绝对正义的!一旦拦截某一事件,剩余的都会被拦住,基本没有子元素的事了(好吧,这里子元素其实有个外挂requestDisallowInterceptTouchEvent,听这名字就知道可以对付父元素)。
事件ACTION_DOWN是个核心事件,如果你这个不消耗 ,那剩余事件你也就别想消耗了,掉别人嘴里了(其实就是父元素);如果你消耗了,就算你不想吃了,别人也吃不到(就是父元素),相当于就是扔掉了。
View的enable问题,别看我是植物人(disable),只要我有嘴(clickable或longclickable为true)就会吃掉事件(返回true)。
貌似书上这里讨论的多是事件分发的冲突,没有太涉及到滑动冲突,一个View只要消耗掉down和up事件就可以完成click操作,View事件分发说到底其实是父元素与子元素的博弈与合作。