Start:
Activity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("June", "dispatchTouchEvent: Activity dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e("June", "Activity onTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("June", "Activity onTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_CANCEL:
Log.e("June", "Activity onTouchEvent ACTION_CANCEL");
break;
case MotionEvent.ACTION_UP:
Log.e("June", "Activity onTouchEvent ACTION_UP");
break;
default:
break;
}
Log.e("June", "onTouchEvent: Activity onTouchEvent");
return super.onTouchEvent(event);
}
}
CustomLinearLayout:
public class CustomLinearLayout extends LinearLayout {
public CustomLinearLayout(Context context) {
super(context);
}
public CustomLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("June", "onInterceptTouchEvent: ViewGroup onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("June", "dispatchTouchEvent: ViewGroup dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e("June", "ViewGroup onTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("June", "ViewGroup onTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_CANCEL:
Log.e("June", "ViewGroup onTouchEvent ACTION_CANCEL");
break;
case MotionEvent.ACTION_UP:
Log.e("June", "ViewGroup onTouchEvent ACTION_UP");
break;
default:
break;
}
Log.e("June", "onTouchEvent: ViewGroup onTouchEvent");
return super.onTouchEvent(event);
}
}
CustomTextView:
public class CustomTextView extends android.support.v7.widget.AppCompatTextView {
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.e("June", "dispatchTouchEvent: View dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e("June", "View onTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("June", "View onTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_CANCEL:
Log.e("June", "View onTouchEvent ACTION_CANCEL");
break;
case MotionEvent.ACTION_UP:
Log.e("June", "View onTouchEvent ACTION_UP");
break;
default:
break;
}
Log.e("June", "onTouchEvent: View onTouchEvent");
return super.onTouchEvent(event);
}
}
Preview:

1、全部return super,点击页面查看日志:

可以看出我们没有对控件里面的方法进行重写或更改返回值,而直接用super调用父类的默认实现,那么整个事件流向应该是从Activity---->ViewGroup--->View 从上往下调用dispatchTouchEvent方法,一直到叶子节点(View)的时候,再由View--->ViewGroup--->Activity从下往上调用onTouchEvent方法。
2、将Activity中的dispatchTouchEvent() reture true
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("June", "dispatchTouchEvent: Activity dispatchTouchEvent");
return true;
}

根据日志可以看出点击事件并没有往下层的View去传递,也没有调用onTouchEvent()方法;
将Activity中的dispatchTouchEvent() return super ,CustomLinearLayout中的dispatchTouchEvent() return true
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("June", "dispatchTouchEvent: ViewGroup dispatchTouchEvent");
return true;
}

最顶层Activity依然正常分发事件到ViewGroup中停止往下分发给子View,也没有调用任何onTouchEvent()方法;
重复上述步骤将CustomTextView中的dispatchTouchEvent()方法return true

同样;
将CustomTextView中的onTouchEvent()方法return true
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e("June", "View onTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("June", "View onTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_CANCEL:
Log.e("June", "View onTouchEvent ACTION_CANCEL");
break;
case MotionEvent.ACTION_UP:
Log.e("June", "View onTouchEvent ACTION_UP");
break;
default:
break;
}
Log.e("June", "onTouchEvent: View onTouchEvent");
return true;
}

分发事件依然正常进行,消费事件在最底层的View中停止向上传递;(同样的return true就不多示意)
结论:dispatchTouchEvent 和 onTouchEvent 一旦return true,事件就停止传递了(到达终点)(没有谁能再收到这个事件)。看下图中只要return true事件就没再继续传下去了,对于return true我们经常说事件被消费了,消费了的意思就是事件走到这里就是终点,不会往下传,没有谁能再收到这个事件了
3、将CustomLinearLayout中的dispatchTouchEvent()方法return false
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("June", "dispatchTouchEvent: ViewGroup dispatchTouchEvent");
return false;
}

下面是将CustomTextView中的dispatchTouchEvent()方法return false的Log日志

可以看出将dispatchTouchEvent()方法return false,事件都会回传给父View的onTouchEvent()方法去进行处理
下面我们将CustomLinearLayoutonTouchEvent() return false看一下什么情况:

可以看出来好像跟上面的全部return super日志输出是一样的?理一下逻辑:因为只有CustomLinearLayoutonTouchEvent() return false 其他的都是return super ,所以Activity传递给ViewGroup传递给子View,子View调用onTouchEvent()向上传递给ViewGroup调用onTouchEvent()传递给Activity调用onTouchEvent(),那没错了,就是一样的。(CustomTextView的onTouchEvent()return false就不过多展示)
结论:对于dispatchTouchEvent() 返回 false ,事件停止往子View传递和分发同时开始往父控件回溯(父控件的onTouchEvent()开始从下往上回传直到某个onTouchEvent() return true),事件分发机制就像递归,return false 的意义就是递归停止然后开始回溯。对于onTouchEvent() return false 就比较简单了,它就是不消费事件,并让事件继续往父控件的方向从下往上流动。
接下来看一下ViewGroup中的onInterceptTouchEvent()方法
Inercept:拦截,意思就是ViewGroup每次在做分发的时候,问一问拦截器要不要拦截(问问自己这个事件要不要自己来处理)如果要自己处理那就在onInterceptTouchEvent()方法中 return true就会交给自己的onTouchEvent()的处理,如果不拦截就是继续往子控件往下传。默认是不会去拦截的,因为子View也需要这个事件,所以onInterceptTouchEvent()拦截器return super.onInterceptTouchEvent()和return false是一样的,是不会拦截的,事件会继续往子View的dispatchTouchEvent()传递。
总结一下吧:
- 对于 dispatchTouchEvent(),onTouchEvent(),return true是终结事件传递。return false 是回溯到父View的onTouchEvent()方法。
- ViewGroup 想把自己分发给自己的onTouchEvent,需要拦截器onInterceptTouchEvent()方法return true 把事件拦截下来。
- ViewGroup 的拦截器onInterceptTouchEvent() 默认是不拦截的,所以return super.onInterceptTouchEvent() = return false;
- View 没有拦截器,为了让View可以把事件分发给自己的onTouchEvent(),View的dispatchTouchEvent()默认实现(super)就是把事件分发给自己的onTouchEvent()
End;
本文深入解析Android中事件分发机制,包括Activity、ViewGroup和View的dispatchTouchEvent与onTouchEvent方法工作原理,以及ViewGroup的onInterceptTouchEvent方法如何决定事件是否被拦截。
1429

被折叠的 条评论
为什么被折叠?



