一直对事件分发的源码不是特别了解,今天重点关注了一下,感觉有点自己的体会吧,写下来记录一下心得。
事件分发大体可以分为View的事件分发和ViewGroup的事件分发,我们先来查看下比较简单点的View的事件
1、事件流程
我们首先通过点击一个Button按钮,查看一下Button的事件怎么走的:
public class MyButton extends Button {
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.i("ricky", "dispatchTouchEvent:action--"+event.getAction()+"---view:MyButton");
return super.dispatchTouchEvent(event);
// return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("ricky", "onTouchEvent:action--"+event.getAction()+"---view:MyButton");
return super.onTouchEvent(event);
}
}
我们在activity里面实现下面这俩个方法
@Override
public void onClick(View v) {
Log.i("ricky", "OnClickListener----view:"+v);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("ricky", "OnTouchListener:acton--"+event.getAction()+"----view:"+v);
return false;
}
打印结果:
06-19 13:11:15.350 24121-24121/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: OnTouchListener:acton--1----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: onTouchEvent:action--1
06-19 13:11:15.422 24121-24121/com.example.shijiantest I/ricky: OnClickListener----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
我们可以总结一下大体的流程为:ispatchTouchEvent-->onTouchListener---return false-->onTouchEvent
下面我们可以猜想一下如果我在 dispatchTouchEvent 方法里面返回true和false会有什么区别,我们带着猜想看下核心源码:
public boolean dispatchTouchEvent(MotionEvent event) {
...
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
...
}
我们可以在其中发现dispatchTouchEvent方法返回值取决于mOnTouchListener、和onTouchEvent和ENABLED。
如果view为disenable,则:onTouchListener里面不会执行,但是会执行onTouchEvent(event)方法;
如果onTouch方法返回true,表示消耗这次事件。down会执行,但是up事件是无法到达onClickListener;
如果onTouch方法返回false,不会消耗此事件。
下面我们通过打印看下我们分析的对不对:
1、dispatchTouchEvent 返回super.dispatchTouchEvent(event); onTouchEvent 返回false //super.onTouchEvent(event);
06-19 13:25:27.884 28410-28410/com.example.shijiantest I/ricky: dispatchTouchEvent:action--0
06-19 13:29:25.648 30033-30033/com.example.shijiantest I/ricky: super.dispatchTouchEvent(event)--false
06-19 13:25:27.885 28410-28410/com.example.shijiantest I/ricky: OnTouchListener:acton--0----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ........ 0,0-264,144 #7f070022 app:id/button}
06-19 13:25:27.885 28410-28410/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:25:27.899 28410-28410/com.example.shijiantest I/ricky: OnTouchListener:acton--0----view:android.widget.LinearLayout{416a794 V.E...C.. .......D 0,0-1080,1680 #7f07004a app:id/layout}
06-19 13:25:27.969 28410-28410/com.example.shijiantest I/ricky: OnTouchListener:acton--1----view:android.widget.LinearLayout{416a794 V.E...C.. ...P.... 0,0-1080,1680 #7f07004a app:id/layout}
06-19 13:25:27.970 28410-28410/com.example.shijiantest I/ricky: OnClickListener----view:android.widget.LinearLayout{416a794 V.E...C.. ...P.... 0,0-1080,1680 #7f07004a app:id/layout}
2、 dispatchTouchEvent 返回super.dispatchTouchEvent(event); onTouchEvent 返回true //super.onTouchEvent(event);
06-19 13:26:50.939 28986-28986/com.example.shijiantest I/ricky: dispatchTouchEvent:action--0
06-19 13:29:25.648 30033-30033/com.example.shijiantest I/ricky: super.dispatchTouchEvent(event)--true
06-19 13:26:50.939 28986-28986/com.example.shijiantest I/ricky: OnTouchListener:acton--0----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ........ 0,0-264,144 #7f070022 app:id/button}
06-19 13:26:50.939 28986-28986/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:26:51.049 28986-28986/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1
06-19 13:26:51.049 28986-28986/com.example.shijiantest I/ricky: OnTouchListener:acton--1----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
06-19 13:26:51.049 28986-28986/com.example.shijiantest I/ricky: onTouchEvent:action--1
06-19 13:26:51.049 28986-28986/com.example.shijiantest I/ricky: OnClickListener----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
可以发现当我们在onTouchEvent 返回true是会执行消耗这次事件,当onTouchEvent返回false时不会执行view的onTouch事件,而是执行的父类的事件。
3、dispatchTouchEvent 返回true super.dispatchTouchEvent(event);
dispatchTouchEvent true super.dispatchTouchEvent(event); onTouchEvent true super.onTouchEvent(event);
06-19 13:11:15.350 24121-24121/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: OnTouchListener:acton--1view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: onTouchEvent:action--1
06-19 13:11:15.422 24121-24121/com.example.shijiantest I/ricky: OnClickListener----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}dispatchTouchEvent true super.dispatchTouchEvent(event); onTouchEvent false super.onTouchEvent(event);
06-19 13:13:11.212 24697-24697/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:13:11.312 24697-24697/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1
06-19 13:13:11.313 24697-24697/com.example.shijiantest I/ricky: OnTouchListener:acton--1----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
06-19 13:13:11.313 24697-24697/com.example.shijiantest I/ricky: onTouchEvent:action--1
06-19 13:13:11.315 24697-24697/com.example.shijiantest I/ricky: OnClickListener----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
我们发现不管 onTouchEvent返回true或false都会执行OnClickListener事件,反之都走的父类的事件。
还有个重要的问题,我在测试的时候发现
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.i("ricky", "dispatchTouchEvent:action--"+event.getAction()+"---view:MyButton");
super.dispatchTouchEvent(event);
return false;
}
我们经常会漏掉super.dispatchTouchEvent(event);这个调用,这个是走的父布局的方法,如果我们不去调用那么我们的dispatchTouchEvent就没有什么意义啦。当然也是视情况而定,我们一般会调用这个方法,否则会经常出现一些奇怪的现象。
今天就主要介绍下View的事件吧,下篇在去做ViewGroup的总结。