//可能是我们村写的最好的
一直对Android事件分发的问题,搞的云里雾里的,正所谓念念不忘,必有回响,今日得空,整理一个文章
demo程序很简单,AMainActivity设置了一个简单的layout,BViewGroupxxx继承自 ViewGroup,CView继承自 View.
对于事件分发,各个类都包含了几个重要的方法。
Activity中包含了两个重要的方法
dispatchTouchEvent
onTouchEvent
ViewGroup 中包含了三个重要的方法
dispatchTouchEvent
onInterceptTouchEvent
onTouchEvent
View 中包含了两个重要的方法
dispatchTouchEvent
onTouchEvent
对于类名以及log出现的多个'x',主要是为了打印日志的长度一致,方便分析
AMainActivity
BViewGroupxxx
CViewxxxxxxxx
dispatchTouchEventxxx
onInterceptTouchEvent
onTouchEventxxxxxxxxx
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.vphealthy.viewgroupdemo.BViewGroupxxx
android:layout_width="200dp"
android:layout_height="200dp"
android:background="@color/colorPrimary">
<com.vphealthy.viewgroupdemo.CViewxxxxxxxx
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorAccent" />
</com.vphealthy.viewgroupdemo.BViewGroupxxx>
</LinearLayout>
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "dispatchTouchEventxxx ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "dispatchTouchEventxxx ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "dispatchTouchEventxxx ACTION_UP");
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_UP");
break;
}
return super.onTouchEvent(ev);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "dispatchTouchEventxxx ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "dispatchTouchEventxxx ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "dispatchTouchEventxxx ACTION_UP");
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "onInterceptTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "onInterceptTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "onInterceptTouchEvent ACTION_UP");
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_UP");
break;
}
return super.onTouchEvent(ev);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "dispatchTouchEventxxx ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "dispatchTouchEventxxx ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "dispatchTouchEventxxx ACTION_UP");
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
以下所有的操作都只是一种,按下->移动->抬起
#针对View的分析
可以看到当我们所有的事件回复都是super时,
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
CViewxxxxxxxx.dispatchTouchEventxxx 返回super,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回super,
日志如下
//Down事件
15:42:41.720 25128-25128/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_DOWN
15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_DOWN
15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_DOWN
15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_DOWN
//MOVE事件
15:50:09.583 25376-25376/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
15:50:08.566 25376-25376/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_MOVE
//UP事件
15:42:41.763 25128-25128/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
15:42:41.763 25128-25128/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_UP
Down事件的流程是 Activity->ViewGroup->View->ViewGroup->Activity,
日志传递流程是 AMainActivity.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.dispatchTouchEventxxx->BViewGroupxxx.onInterceptTouchEvent
日志传递流程是 CViewxxxxxxxx.dispatchTouchEventxxx->CViewxxxxxxxx.onTouchEventxxxxxxxxx
日志传递流程是 BViewGroupxxx.onTouchEventxxxxxxxxx
日志传递流程是 AMainActivity.onTouchEventxxxxxxxxx
UP&move事件则只在MainActivity中处理,为什么不传递给ViewGroup->View?
当Down传递到View.onTouchEvent,不View被消费时,还会回传到ViewGroup.onTouchEvent,MainActivity.onTouchEvent,
并且后续的MOVE,UP事件也不会再传递给ViewGroup和View了。
问题一 后续的MOVE,UP事件不会再传递给ViewGroup和View?
现在我们将View中的onTouchEvent方法返回false,其他均为super,与(A.1)的现象一致。
现在我们将View中的onTouchEvent方法返回true,其他均为super。
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
CViewxxxxxxxx.dispatchTouchEventxxx 返回super,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true,
日志如下
//Down事件
15:52:52.666 25944-25944/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
15:52:52.667 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
15:52:52.667 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
15:52:52.667 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_DOWN
15:52:52.667 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_DOWN
//MOVE事件
15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_MOVE
15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_MOVE
15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_MOVE
15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_MOVE
//UP事件
15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_UP
15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_UP
15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_UP
15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_UP
Down事件的流程是 MainActivity->ViewGroup->View
日志传递流程是 AMainActivity.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.dispatchTouchEventxxx->BViewGroupxxx.onInterceptTouchEvent
日志传递流程是 CViewxxxxxxxx.dispatchTouchEventxxx->CViewxxxxxxxx.onTouchEventxxxxxxxxx
UP&move事件也同于Down事件
这里与(A.1)相比就发现了2个区别
1.View.onTouchEvent返回ture以后,ViewGroup.onTouchEvent以及Activity.onTouchEvent不会再调用了
2.View.onTouchEvent返回ture以后,down和move方法不只在Activity执行了,也会分发给ViewGroup和View
现在我们将ViewGroup中的onTouchEvent方法返回true,其他均super。
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回true,
CViewxxxxxxxx.dispatchTouchEventxxx 返回super,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回super,
日志如下
//Down事件
17:51:40.790 2159-2159/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
17:51:40.791 2159-2159/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
17:51:40.791 2159-2159/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
17:51:40.791 2159-2159/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_DOWN
17:51:40.791 2159-2159/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_DOWN
17:51:40.791 2159-2159/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_DOWN
//MOVE事件
17:51:40.798 2159-2159/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
17:51:40.798 2159-2159/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_MOVE
17:51:40.798 2159-2159/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_MOVE
//up事件
17:51:41.007 2159-2159/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
17:51:41.007 2159-2159/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_UP
17:51:41.007 2159-2159/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_UP
Down事件的流程是 MainActivity->ViewGroup->View
日志传递流程是 AMainActivity.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.dispatchTouchEventxxx->BViewGroupxxx.onInterceptTouchEvent
日志传递流程是 CViewxxxxxxxx.dispatchTouchEventxxx->CViewxxxxxxxx.onTouchEventxxxxxxxxx->BViewGroupxxx.onTouchEventxxxxxxxxx
UP&move事件则不同于Down事件
日志传递流程是 AMainActivity.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.dispatchTouchEventxxx->BViewGroupxxx.onTouchEventxxxxxxxxx,
发现了么,BViewGroupxxx.onInterceptTouchEvent不调用了,直接就调用了BViewGroupxxx.onTouchEventxxxxxxxxx,子类的onTouchEventxxxxxxxxx返回super,即不处理时,BViewGroupxxx的UP&move事件的onInterceptTouchEvent都不分发了?
问题二 BViewGroupxxx的UP&move事件的onInterceptTouchEvent为什么不分发了
当Activity,ViewGroup 返回均为super时且View的dispatchTouchEvent返回super时,
只有View的onTouchEvent返回ture;之后的move及up事件才会再传给view.
当Activity,ViewGroup,View返回均为super时,只有ViewGroup的onTouch返回true, BViewGroupxxx后续的UP&move事件的onInterceptTouchEvent都不分发了?
现在我们将View中的dispatchTouchEvent也返回true,onTouchEvent方法返回true,其他均为super。
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
CViewxxxxxxxx.dispatchTouchEventxxx 返回true,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true,
日志如下
//Down事件
16:12:50.244 27405-27405/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
16:12:50.245 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
16:12:50.245 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
16:12:50.245 27405-27405/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_DOWN
//MOVE事件
16:12:50.499 27405-27405/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
16:12:50.500 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_MOVE
16:12:50.500 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_MOVE
16:12:50.500 27405-27405/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_MOVE
//UP事件
16:12:50.680 27405-27405/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
16:12:50.681 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_UP
16:12:50.681 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_UP
16:12:50.681 27405-27405/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_UP
Down事件的流程是 MainActivity->ViewGroup->View
日志传递流程是 AMainActivity.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.dispatchTouchEventxxx->BViewGroupxxx.onInterceptTouchEvent
日志传递流程是 CViewxxxxxxxx.dispatchTouchEventxxx
UP&move事件也同于Down事件
这里与情况与(A.3)相比就发现了1个区别
1.当事件传递到View.dispatchTouchEvent返回ture时,View.onTouchEvent不会再被执行,
现在我们将View中的dispatchTouchEvent返回true,View.onTouchEvent方法返回false,其他均super。
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
CViewxxxxxxxx.dispatchTouchEventxxx 返回true,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回false,
日志与(B.1)的现象一致。
现在我们将View中的dispatchTouchEvent返回true,其他均为super。
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
CViewxxxxxxxx.dispatchTouchEventxxx 返回true,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true,
日志与(B.1)的现象一致。
现在我们将View中的dispatchTouchEvent返回true时,表示事件被View.dispatchTouchEvent消费,
View.onTouchEvent无论返回什么都不会被调用。
原因可以在View.java的源码可以找到
public boolean dispatchTouchEvent(MotionEvent event) {
// If the event should be handled by accessibility focus first.
if (event.isTargetAccessibilityFocus()) {
// We don't have focus or no virtual descendant has it, do not handle the event.
if (!isAccessibilityFocusedViewOrHost()) {
return false;
}
// We have focus and got the event, then use normal event dispatch.
event.setTargetAccessibilityFocus(false);
}
boolean result = false;
....
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) { //看这里
result = true;
}
}
....
}
当CViewxxxxxxxx的dispatchTouchEvent不调用super.dispatchTouchEvent时,
View的onTouchEvent当然不会被执行,
View的onTouchEvent不被执行,CViewxxxxxxxx.onTouchEvent形同虚设
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
CViewxxxxxxxx.dispatchTouchEventxxx 返回false,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回super,
--
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
CViewxxxxxxxx.dispatchTouchEventxxx 返回false,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回false,
--
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
CViewxxxxxxxx.dispatchTouchEventxxx 返回false,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true,
由情况B得出的结论,当CViewxxxxxxxx的dispatchTouchEvent返回false时,CViewxxxxxxxx.onTouchEvent也是形同虚设,我们来看一下会发生什么
//Down事件
19:09:03.318 4794-4794/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
19:09:03.319 4794-4794/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
19:09:03.319 4794-4794/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
19:09:03.319 4794-4794/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_DOWN
19:09:03.319 4794-4794/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_DOWN
19:09:03.319 4794-4794/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_DOWN
//MOVE事件
19:09:03.350 4794-4794/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
19:09:03.350 4794-4794/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_MOVE
//UP事件
19:09:03.503 4794-4794/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
19:09:03.503 4794-4794/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_UP
Down事件的流程是 Activity->ViewGroup->View->ViewGroup->Activity,
日志传递流程是 AMainActivity.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.dispatchTouchEventxxx->BViewGroupxxx.onInterceptTouchEvent
日志传递流程是 CViewxxxxxxxx.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.onTouchEventxxxxxxxxx
日志传递流程是 AMainActivity.onTouchEventxxxxxxxxx
UP&move事件则只在MainActivity中处理,为什么不传递给ViewGroup->View?
问题三 当CViewxxxxxxxx的dispatchTouchEvent返回false时,如何调用上一层的onTouchEventxxxxxxxxx
这时我们发现了跟(情况A.1)的现象很相似,不同的在于CViewxxxxxxxx.dispatchTouchEventxxx后,不再执行CViewxxxxxxxx.onTouchEventxxxxxxxxx
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
CViewxxxxxxxx.dispatchTouchEventxxx[super]
CViewxxxxxxxx.onTouchEventxxxxxxxxx [super]
说明:CViewxxxxxxxx.onTouchEventxxxxxxxxx(down)会被调用,且再向BViewGroupxxx及AMainActivity回溯onTouchEventxxxxxxxxx,
Move,Up事件只在AMainActivity才会有回调,不会分发到BViewGroupxxx及CViewxxxxxxxx,
CViewxxxxxxxx.onTouchEventxxxxxxxxx [false]
说明:CViewxxxxxxxx.onTouchEventxxxxxxxxx(down)会被调用,且再向BViewGroupxxx及AMainActivity回溯onTouchEventxxxxxxxxx,
Move,Up事件只在AMainActivity才会有回调,不会分发到BViewGroupxxx及CViewxxxxxxxx,
CViewxxxxxxxx.onTouchEventxxxxxxxxx [true]
说明:CViewxxxxxxxx.onTouchEventxxxxxxxxx(down,move,up)均会被调用,然后结束,
不会再向BViewGroupxxx及AMainActivity回溯onTouchEventxxxxxxxxx
CViewxxxxxxxx.dispatchTouchEventxxx[true]
CViewxxxxxxxx.onTouchEventxxxxxxxxx [super]
CViewxxxxxxxx.onTouchEventxxxxxxxxx [false]
CViewxxxxxxxx.onTouchEventxxxxxxxxx [true]
说明:CViewxxxxxxxx.onTouchEventxxxxxxxxx(down,move,up)均不会被调用,
Down,Move,Up事件最终会分发到CViewxxxxxxxx.dispatchTouchEventxxx,然后结束,
不会再向BViewGroupxxx及AMainActivity回溯onTouchEventxxxxxxxxx
CViewxxxxxxxx.dispatchTouchEventxxx[false]
CViewxxxxxxxx.onTouchEventxxxxxxxxx [super]
CViewxxxxxxxx.onTouchEventxxxxxxxxx [false]
CViewxxxxxxxx.onTouchEventxxxxxxxxx [true]
说明:CViewxxxxxxxx.onTouchEventxxxxxxxxx(down,move,up)均不会被调用,
Down事件最终会分发到CViewxxxxxxxx.dispatchTouchEventxxx,然后结束,
Move,Up事件只在AMainActivity才会有回调,不会分发到BViewGroupxxx.dispatchTouchEventxxx
View的操作分析结束了,接着我们来分析ViewGroup的处理。
到此我们明白了事件处理的2个原则
1.dispatchTouchEvent是用于自上而下的分发事件,
只有当返回super时,才会被分发到下一步;
返回ture时,所有事件被自己消费;
返回false时,会回溯给自己上一层的对象的onTouchEvent去处理
2.onTouchEvent的事件消费是自下而上的,下面不消费就一直向上传递,直到被消费才中止。
3.由Down事件的消费情况来确定了消费的目标对象,再来判断之后的move,up的事件,要具体分发到哪里
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
表示事件会在Activity正常分发
BViewGroupxxx.dispatchTouchEventxxx 返回true,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
表示事件会在viewGroup不会被分发,
CViewxxxxxxxx.dispatchTouchEventxxx 返回super,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true,
表示事件会在view正常分发且消费
根据view的情况可以猜想,Activity的事件只会分发到ViewGroup的dispatchTouchEvent,然后不再走ViewGroup.onInterceptTouchEvent及ViewGroup.onTouchEvent,因为被ViewGroup的dispatchTouchEvent消费了,也不会回溯到Activity的onTouchEvent
//Down事件
10:09:55.691 7736-7736/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
10:09:55.692 7736-7736/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
//Move事件
10:09:55.822 7736-7736/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
10:09:55.822 7736-7736/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_MOVE
//UP事件
10:09:56.540 7736-7736/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
10:09:56.540 7736-7736/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_UP
根据日志情况来看,与我们猜想的一致
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
表示事件会在Activity正常分发
BViewGroupxxx.dispatchTouchEventxxx 返回false,
BViewGroupxxx.onInterceptTouchEvent 返回super,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
表示事件会在viewGroup不会被分发,
CViewxxxxxxxx.dispatchTouchEventxxx 返回super,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true,
表示事件会在view正常分发且消费
根据view的情况可以猜想,Activity的事件只会分发到ViewGroup的dispatchTouchEvent,然后不再走ViewGroup.onInterceptTouchEvent及ViewGroup.onTouchEvent,因为没有被ViewGroup的dispatchTouchEvent消费,所以会回溯到Activity的onTouchEvent,且后续的Move,Up事件只在AMainActivity才会有回调,不会分发到BViewGroupxxx.dispatchTouchEventxxx
//Down事件
10:17:32.941 8054-8054/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
10:17:32.942 8054-8054/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
10:17:32.942 8054-8054/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_DOWN
//Move事件
10:17:33.106 8054-8054/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
10:17:33.106 8054-8054/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_MOVE
//Up事件
10:17:33.519 8054-8054/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
10:17:33.519 8054-8054/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_UP
根据日志情况来看,与我们猜想的一致
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
表示事件会在Activity正常分发
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回false,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
表示事件会在viewGroup不会被分发,
CViewxxxxxxxx.dispatchTouchEventxxx 返回super,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true,
表示事件会在view正常分发且消费
我们看下会发生什么
//Down事件
10:31:17.620 8753-8753/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
10:31:17.620 8753-8753/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
10:31:17.620 8753-8753/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
10:31:17.620 8753-8753/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_DOWN
10:31:17.620 8753-8753/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_DOWN
//Move事件
10:31:17.645 8753-8753/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
10:31:17.645 8753-8753/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_MOVE
10:31:17.645 8753-8753/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_MOVE
10:31:17.645 8753-8753/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_MOVE
10:31:17.645 8753-8753/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_MOVE
//Up事件
10:31:18.062 8753-8753/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
10:31:18.062 8753-8753/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_UP
10:31:18.062 8753-8753/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_UP
10:31:18.062 8753-8753/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_UP
10:31:18.062 8753-8753/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_UP
我们发现所有的事件(Down,Move,Up)都经过了三个类的的方法,与(针对View的分析中的情况A.4)结果一致,而在前者中,BViewGroupxxx.onInterceptTouchEvent的返回值为super,这也说明BViewGroupxxx.onInterceptTouchEvent的返回值为(false或super时),现象是一致。
这点可以从ViewGroup.onInterceptTouchEvent的源码中得知
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
&& ev.getAction() == MotionEvent.ACTION_DOWN
&& ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
&& isOnScrollbarThumb(ev.getX(), ev.getY())) {
return true;
}
return false;
}
ViewGroup.onInterceptTouchEvent默认返回的就是false,那么调用super,返回的不就是false么,故ViewGroup.onInterceptTouchEvent返回false或super时,现象一致。
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
表示事件会在Activity正常分发
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回true,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,
表示事件会在viewGroup不会被分发,
CViewxxxxxxxx.dispatchTouchEventxxx 返回super,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true,
表示事件会在view正常分发且消费
到目前为止,我们还不清楚当事件被ViewGroup拦截会发生什么
//Down事件
10:53:23.939 10154-10154/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
10:53:23.940 10154-10154/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
10:53:23.940 10154-10154/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
10:53:23.940 10154-10154/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_DOWN
10:53:23.940 10154-10154/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_DOWN
//Move事件
10:53:24.028 10154-10154/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
10:53:24.028 10154-10154/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_MOVE
//UP事件
10:53:24.218 10154-10154/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
10:53:24.218 10154-10154/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_UP
Down事件的流程是 Activity->ViewGroup->Activity,
日志传递流程是 AMainActivity.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.onInterceptTouchEvent
日志传递流程是 BViewGroupxxx.onTouchEventxxxxxxxxx
日志传递流程是 AMainActivity.onTouchEventxxxxxxxxx
发现了没有,这里根本没有CViewxxxxxxxx的事情,被BViewGroupxxx拦截之后,直接传递给BViewGroupxxx.onTouchEventxxxxxxxxx,并且返回的是super,所以还会向上回溯,返回给AMainActivity
Move,Up及事件只在AMainActivity传递
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
表示事件会在Activity正常分发
BViewGroupxxx.dispatchTouchEventxxx 返回super,
BViewGroupxxx.onInterceptTouchEvent 返回true,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回true,
表示事件会在viewGroup不会被分发,
CViewxxxxxxxx.dispatchTouchEventxxx 返回super,
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true,
表示事件会在view正常分发且消费
到目前为止,我们还不清楚当事件被ViewGroup拦截会发生什么
//Down事件
11:08:43.132 10592-10592/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
11:08:43.133 10592-10592/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
11:08:43.133 10592-10592/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
11:08:43.133 10592-10592/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_DOWN
//Move事件
11:08:43.156 10592-10592/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
11:08:43.156 10592-10592/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_MOVE
11:08:43.156 10592-10592/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_MOVE
//Up事件
11:08:43.357 10592-10592/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
11:08:43.357 10592-10592/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_UP
11:08:43.357 10592-10592/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_UP
Down事件的流程是 Activity->ViewGroup->Activity,
日志传递流程是 AMainActivity.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.dispatchTouchEventxxx
日志传递流程是 BViewGroupxxx.onInterceptTouchEvent
日志传递流程是 BViewGroupxxx.onTouchEventxxxxxxxxx
发现了没有,Down事件不会回溯给AMainActivity了,因为已经被BViewGroupxxx.onTouchEventxxxxxxxxx消费了,所以不再回溯
Move,Up及事件也会传递给BViewGroupxxx,不同的在于不会再调用了onInterceptTouchEvent?
//Down事件
11:23:23.161 10836-10836/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
11:23:23.162 10836-10836/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
11:23:23.162 10836-10836/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
11:23:23.162 10836-10836/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_DOWN
11:23:23.162 10836-10836/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_DOWN
//Move事件
11:23:23.172 10836-10836/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
11:23:23.172 10836-10836/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_MOVE
//Up事件
11:23:23.315 10836-10836/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
11:23:23.316 10836-10836/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_UP
到这已经没有什么好说的了,因为BViewGroupxxx.onTouchEventxxxxxxxxx返回false,也就是说BViewGroupxxx.onTouchEventxxxxxxxxx不消费事件,那么Down事件要回溯给AMainActivity.onTouchEventxxxxxxxxx,且后续的move,up事件,不会再给BViewGroupxxx了。
#针对ViewGroup的分析总结
至此我们的分析涉及了以下的多种情况
AMainActivity.dispatchTouchEventxxx 返回super
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super,true,false,
BViewGroupxxx.onInterceptTouchEvent 返回super,true,false,
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super,true,false,
CViewxxxxxxxx.dispatchTouchEventxxx 返回super
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true
我们可以得到以下的结论
当ViewGroup的dispatchTouchEvent返回true时,与View的dispatchTouchEvent处理一致,都是交给自己处理,不会再分发了。
当ViewGroup的onInterceptTouchEvent返回true时,会传递给ViewGroup的onTouchEvent去处理
ViewGroup的onTouchEvent的处理与View的onTouchEvent的处理一致,
从源码可知,其实ViewGroup就是继承View的,且ViewGroup并没有复写onTouchEvent方法
AMainActivity.dispatchTouchEventxxx 返回true
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super
BViewGroupxxx.onInterceptTouchEvent 返回super
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super
CViewxxxxxxxx.dispatchTouchEventxxx 返回super
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true
看看会发生什么
11:39:26.814 11282-11282/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
11:39:26.926 11282-11282/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
11:39:27.177 11282-11282/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
11:39:27.177 11282-11282/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
事件少的可怜,所有的事件都只在AMainActivity: dispatchTouchEventxxx中调用,不分发给自己BViewGroupxxx.dispatchTouchEventxxx 以及AMainActivity: onTouchEventxxxxxxxxx,
AMainActivity.dispatchTouchEventxxx 返回false
AMainActivity.onTouchEventxxxxxxxxx 返回super,
BViewGroupxxx.dispatchTouchEventxxx 返回super
BViewGroupxxx.onInterceptTouchEvent 返回super
BViewGroupxxx.onTouchEventxxxxxxxxx 返回super
CViewxxxxxxxx.dispatchTouchEventxxx 返回super
CViewxxxxxxxx.onTouchEventxxxxxxxxx 返回true
看看会发生什么
11:42:10.812 12416-12416/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
11:42:10.921 12416-12416/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
11:42:10.985 12416-12416/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
11:42:10.985 12416-12416/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
哈哈,本来以为会调用onTouchEvent,但是发现了跟情况G.1一致,
仔细想想也是,按照之前的现象分析,当Activity.dispatchTouchEvent返回false时,
应该给上一层的onTouchEvent去处理,可是Activity已经是最上层了,哪里还有onTouchEvent给它调用呢。
对于Activity.onTouchEvent的返回值其实没有讨论的必要性,因为已经是最上层了,返回什么都不重要了。
至此,涉及Activity,ViewGroup,View事件的所有情况,我们都将日志打印分析了一遍。
问题一 当所有都返回super时,UP&move事件则只在MainActivity中处理,为什么不传递给ViewGroup->View?
问题二 当Activity,ViewGroup,View返回均为super时,只有ViewGroup的onTouch返回true,
ViewGroup后续的UP&move事件的onInterceptTouchEvent都不分发了?
问题三 当CViewxxxxxxxx的dispatchTouchEvent返回false时,如何调用上一层的onTouchEventxxxxxxxxx
答案都在viewgroup中的dispatchTouchEvent的方法中