View事件分发
View本身的事件方法DOWN,MOVE,UP都会按照如下方式进行顺序执行:
dispatchTouchEvent()
setOnTouchListener()
方法中的onTouch()
方法onTouchEvent()
dispatchTouchEvent()源码
在dispatchTouchEvent(MotionEvent event)
中由如下代码段,决定了如上2,3的执行逻辑
public boolean dispatchTouchEvent(MotionEvent event) {
if (!onFilterTouchEventForSecurity(event)) {
return false;
}
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
在此段代码中,第2个if判断中有如下判断
mOnTouchListener!=null
:即调用setOnTouchListener()
方法(mViewFlags & ENABLED_MASK) == ENABLED
:标识View是否启用,大部分情况都为truemOnTouchListener.onTouch(this, event)
: 很关键的一段,此段决定当onTouch()
方法返回true,方法将进入if中,直接返回,此时onTouchEvent()
方法将不再执行。
总结:如果OnTouchListener不为null且返回true,则表示事件被消费,onTouchEvent不会被执行;否则执行onTouchEvent
OnTouchEvent()源码
在View的onTouchEvent()
方法中,有如下处理:
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
//...
return true;
}
该段代码表明,如果View是可以点击或者可以长按的,则一定会返回true。
setOnLongClickListener()和setOnClickListener()执行逻辑
- 如果同时设置了两个方法,则当长按时,是否执行
onClick()
方法取决于setOnLongClickListener()
的返回值类型。 - 如果
setOnLongClickListener()
返回false,则两个方法都会执行 - 如果
setOnLongClickListener()
返回true,则会屏蔽点击事件。
onTouch()方法和onClick()的执行逻辑
- 从上面的分析或者通过源码可知,onTouch()方法是在dispatchTouchEvent()中进行调用的,且其优先于onTouchEvent()方法。
- onClick()方法是在onTouchEvent()中进行判断并调用performClick()方法进行调用的。
总结:onTouch()在onClick()之前进行调用,同时通过onTouch()和onToucEvent()的逻辑关系得出当onTouch()方法返回true时,onTouchEvent()不会执行,则onClick()方法也不会执行
View触摸事件的总结
- View是否调用onTouchEvent()方法,取决于dispatchTouchEvent()的返回值,在平常自定义View的时候,如果我们不重写dispatchTouchEvent()方法,则onTouchEvent()方法返回true,则能够处理触摸,如果返回false,则无法处理触摸事件。
如果重写dispatchTouchEvent()方法,则根据返回值两种情况:
return super.dispatchTouchEvent()
:依然取决于onTouchEvent();return ture/false
:onTouchEvent()将不会被调用。
View 触摸事件顺序为 dispatchTouchEvent() - > onTouch() ->onTouchEvent().View是否能捕获触摸,取决于
dispatchTouchEvent()
返回值,返回true,则消费事件,返回false,则不消费事件。同时View默认实现的dispatchTouchEvent()方法已经实现了当前View下继续分发到onTouchEvent(),同时将onTouchEvent()
结果作为返回值返回。- 通常做法:
dispatchTouchEvent()
返回值一直返回return super.dispatchTouchEvent()
.重写onTouchEvent()
,需要捕获时,强制返回true。。 - 当我们继承自View时,View的自身相关方法返回值,
dispatchTouchEvent()
返回值取决于onTouchEvent()
,onTouchEvent()
返回值,当View属性是clickable时,则返回true,否则返回false。
研究资料
Android触摸屏事件派发机制详解与源码分析一(View篇)
Android View 事件分发机制 源码解析 (上)