Android事件分发机制之View篇
我们在android手机开发中有时会碰到一些这样的问题:1、上下滑动屏幕,ListView并不随之滚动?2、按一些按键(如Button),且已经设置了setOnclickListener相关监听,但按键确实没反应?这是为什么呢?这就是我这篇文章要讲到的Android事件分发。我们通过一个非常简单的例子来讲解一下,这个真的是非常简单:
先来一个Demo示范:
一、Demo的layout文件
activity_main.xml文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" >
<cn.ithm.eventdemo.MyButton
android:id="@+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</LinearLayout>
二、自定义Button
MyButton类文件如下:
public class MyButton extends Button {
private static final String TAG = "MyButton";
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "MyButton dispatchTouchEvent--ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "MyButton dispatchTouchEvent--ACTION_UP");
break;
default:
break;
}
return super.dispatchTouchEvent(event);
// return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "MyButton onTouchEvent--ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "MyButton onTouchEvent--ACTION_UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
}
三、MainActivity.java文件如下:
public class MainActivity extends Activity {
protected static final String TAG = "MainActivity";
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.mybutton);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Log.i(TAG, "MyButton onclick");
}
});
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
switch (arg1.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "MyButton setOnTouchListener--ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "MyButton setOnTouchListener--ACTION_UP");
break;
default:
break;
}
return false;
// return true;
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "MainActivity dispatchTouchEvent--ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "MainActivity dispatchTouchEvent--ACTION_UP");
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
// return true;
}
}
我们准备好上面文件后,就开始研究我们的事件分发了。首先我们点击“hello word”这个按键后,LogCat里打印出如下结果:
![这里写图片描述](https://img-blog.csdn.net/20151226174624368)
从上面的结果我们可以看出,android事件分发的起点是Activity自身的dispatchTouchEvent方法开始的,然后到子View的dispatchTouchEvent->onTouch->onTouchEvent,再是up事件,跟down顺序是相同的,最后执行MyButton的onClick事件。
到这里我们大概清楚了android的事件分发是如何执行的。接下来我们对代码稍作修改,只是把Activity中的dispatchTouchEvent的返回值作一个修改,让其return true; 然后我们再看LogCat的打印结果:
从上面这个结果,我们大吃一惊,后续的touch事件都没有执行。这是什么原因呢?其实很简单啦,就是Activity的dispatchTouchEvent的返回值惹的事,它返回了true,表示Activity已经把事件给消耗掉了,后续的子View不能接收到事件了,所以后面的都没有执行。
好,非常好!我们接下来把代码恢复为最初的模样,然后再button.setOnTouchListener方法中返回true,运行再看打印结果:
我们发现MyButton的onTouchEvent和onClick都没有执行,也是同样的道理,MyButton在onTouch中把事件消耗掉了所以不再往下发了。
四、总结
通过这个简单的demo例子,我们总结如下:
1、Android事件分发之View的顺序是Activity的dispatchTouchEvent->子View的dispatchTouchEvent->子View的OnTouch->子View的onTouchEvent->onClick
2、事件分发是顺序执行的,如果在某一点事件事件被消耗了,则事件不会再往后传了
最后,由于我刚学安卓不久,以上内容写的不好的地方,请批评指正!谢谢