上一篇《Android自定义组件系列【5】——进阶实践(2)》继续对任老师的《可下拉的PinnedHeaderExpandableListView的实现》进行了分析,这一篇计划中间插一段“知识点”,对Android中的事件分发机制进行解析。细心的朋友可能会发现,打开大牛写的Android项目,里面很多组件都是自定义的(这就是为什么界面和体验这么吸引你的原因),但是要灵活的去自定义组件就必须对手势(也就是各种监听)必须熟悉,能处理好事件之间的关系。

先看一段代码:

	@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) {
Log.i(TAG, "onClick");
}
}); button.setOnTouchListener(new OnTouchListener() { @Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "onTouch down");
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "onTouch move");
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "onTouch up");
break;
default:
break;
}
return false;
}
});
}

可以看到onTouch方法会被先调用,然后才调用onClick方法,如果我们将上面onTouch方法的返回值改为true,则onClick方法不会被调用,事件将被onTouch方法消费。

还记得前几篇文章中都会使用一个dispatchTouchEvent的方法吗.

public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}

可以看到在dispatchTouchEvent中调用了onTouch方法,所以会先于onClick方法调用。如果onTouch返回true后dispatcheTouchEvent就会直接返回true则不会再执行其他方法。

在Android系统中每个ViewGroup子类都具有如下三个方法:

public boolean dispatchTouchEvent(MotionEvent event)  :用来分发TouchEvent

public boolean onInterceptTouchEvent(MotionEvent event) :用来拦截TouchEvent

public boolean onTouchEvent(MotionEvent event) :处理TouchEvent

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<com.kris.touch.widget.TouchView
android:id="@+id/view_out"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#fff"
android:gravity="center">
<com.kris.touch.widget.TouchView
android:id="@+id/view_mid"
android:layout_width="300px"
android:layout_height="400px"
android:background="#f00"
android:gravity="center">
<com.kris.touch.widget.TouchView
android:id="@+id/view_center"
android:layout_width="150px"
android:layout_height="150px"
android:background="#000"
android:gravity="center"
android:clickable="true">
</com.kris.touch.widget.TouchView>
</com.kris.touch.widget.TouchView>
</com.kris.touch.widget.TouchView>
</LinearLayout>

首先触摸事件(ACTION_DOWN)发生后,系统调用Activity的dispatchTouchEvent方法,分发事件。根据触摸事件的坐标,将此事件传递给out(最外层)的dispatchTouchEvent处理。out则调用onInterceptTouchEvent方法判断事件是否由自己来处理,还是向下传递给子View.如果out不处理该事件会根据事件产生坐标分发给它的直接子View.

图中center组件是可点击的(clickable)组件,表示能处理Touch事件,所以center中的onInterceptTouchEvent方法将事件传递给center

TouchEvent中,如果返回值是true,则说明消耗(消费)了这个事件,不会再向下传递。如果返回值是false,则没有消耗事件,会继续传递下去。如果center中不会处理事件(android:clickable="false"),事件不会被center的onTouchEvent消费,则事件会层层逆向回到activity。

关于事件分发机制就先了解到这里,下一篇接着分析......

最新文章

  1. Cookie的设置与获取
  2. 使用group_concat 时,设置mysql默认的长度
  3. sql boolean类型
  4. ThoughtWorks微服务架构交流心得
  5. TCP相关知识
  6. javascript-03
  7. PHP IP互换数字[转]
  8. Asp.Net 控件radio 的简单使用
  9. axis WebServices 完美调用天气预报,查询、显示 代码!
  10. 开心菜鸟学习系列笔记-----Javascript(1)
  11. 将DataTable 存到一个集合当中
  12. 在写一点关于MySQL的知识,感觉自己mmd
  13. 【手记】小心在where中使用NEWID()的大坑
  14. TypeError: sequence item 1: expected str instance, int found
  15. maven中央仓库地址(支持db2,informix等)
  16. .NET快速开发平台免费版预发布
  17. C# 实现Jwtbearer Authentication
  18. ERP项目实施记录09
  19. [日常工作]WorkStation 使用端口转发的方式使用宿主机IP地址提供服务
  20. Linux使用imagemagick的convert命令压缩图片、节省服务器空间

热门文章

  1. 轻松学习Linux之用户账户管理及实例
  2. golang 方法内部定义子方法及调用
  3. 关于Webpack详述系列文章 (第二篇)
  4. div的标准盒模型和怪异盒模型
  5. 洛谷——U10783 名字被和谐了
  6. Android滚轮选择器实现
  7. Android实现微信分享及注意事项
  8. ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第一篇:准备工作
  9. How to Rotate Tomcat catalina.out
  10. 洛谷——P1179 数字统计