最近一直在学习有关android事件分发机制的问题,翻阅了各个大牛的书籍以及网上各位码神的博客,自己又写了demo测试并仔细看过源码之后终于算是搞的差不多了,为了防止遗忘,并分享给各位跟我一样懵懂的小伙伴们作为参考,决定写下来作为笔记,第一次写博客,文笔不好请见谅,如有不对之处欢迎指正。
言归正传,我们大家可能都做过需要判断手指在控件上按下移动离开这样类似的功能,我们一般是加setOnTouchListener,即触摸监听,或者有时候我们也会重写onTouchEvent方法,但是这两种监听有什么区别呢?如果都有的话,谁先谁后呢?这两种方法都是带有布尔类型的返回值的,那么true和false对结果有什么影响呢?带着这些问题我们来简单写个demo测试下:
自定义一个View,并重写dispatchTouchEvent和onTouchEvent方法,我直接重写了一个Button
public class MyButton extends Button {
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyButton(Context context) {
super(context);
}
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.v("EventTest", "dispatchTouchEvent ");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.v("EventTest", "onTouchEvent (MyButton)");
return super.onTouchEvent(event);
}
}
主activity的部分代码,我们给按钮加了touch事件监听,并加了click监听
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v("EventTest", "onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.v("EventTest","onTouch (MyButton)"+event.getAction());
return true;
}
});
运行程序,打印日志如下:
首先我们要明白分析事件分发机制其实就是分析MotionEvent对象的传递过程,即点击事件,当MotionEvent产生后,系统会把这个事件在View之间进行传递,这个过程就是分发,典型的事件类型有三种:
ACTION_DOWN--------------手指刚接触屏幕的一瞬间
ACTION_MOVE--------------手指在屏幕上移动的时候
ACTION_UP--------------手指在屏幕上松开的瞬间
一般情况下,一个完整的事件序列会从ACTION_DOWN开始,中间经历个数不等的ACTION_MOVE,最后是ACTION_UP事件,通过以上的日志,我们可以看到点击事件先是触发了dispatchTouchEvent方法,然后是onTouch方法(日志中0代表的是down,2代表的是move,1代表的是up事件),但是却没有执行我们重写的onTouchEvent方法和设置的onclickListener方法,为什么呢,这是因为我们的onTouch方法是带有返回值的,返回值代表是否消耗当前事件,上面的代码返回了true,所以事件被onTouch消耗了,后续的方法就得不到执行。我们继续测试,改一下上面的返回值为false,重新运行程序,日志如下:
这时候我们可以看到onTouchEvent执行了,并且在最后还执行了onClick事件。
这里我们可以总结一下,View的事件执行过程:dispatchTouchEvent->onTouch(如果有的话)-> onTouchEvent->onclick(如果有)
(这是单纯的一个View的事件传递,不包含VewGroup,ViewGroup的后面我们会再做分析)
下面我们从源码上面来分析一下,首先一个View中如果有事件传递,那么先执行的肯定是dispatchTouch