android事件分发机制
来源:互联网 发布:windows kill进程命令 编辑:程序博客网 时间:2024/06/08 18:35
写在前面:看了《android群英传》的事件分发后,结合自己的一些理解,整理了一下,记录如下:
首先,在我的前面博客自定义view解析中有讲到view的结构树,它是由viewgroup和view相互嵌套组成的树形结构,一个viewgroup里可以放view也可以放其他viewgroup,然后逐层分发,那么当点击事件发生的时候,是由viewgroup执行呢?还是view执行?因此这里就产生了“事件拦截这一说法”。
然后,事件的分发和拦截的核心函数:
①dispatchTouchEvent
②onInterceptTouchEvent
③onTouchEvent
顾名思义,第一个是分发触摸事件,第二个是拦截触摸事件,第三个是处理触摸事件。
注意:只有ViewGroup类里才能重写onInterceptTouchEvent
顺序:(经过我个人的研究发现)事件最开始获取是在ViewGroup所处的Activity里得到,然后经过层层dispatch到达最小的view,再处理事件逻辑。
下面我给出代码验证一波:
public class MainActivity extends Activity { private MyLinearLayout m1; private MyButton m2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); m1 = new MyLinearLayout(this); m2 = new MyButton(this); m2.setText("点我!"); setContentView(m1); m1.addView(m2); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("test", "MainActivity dispatchTouchEvent"); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("test", "MainActivity onTouchEvent"); return super.onTouchEvent(event); }}class MyLinearLayout extends LinearLayout { public MyLinearLayout(Context context) { super(context); } public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("test", "MyLinearLayout dispatchTouchEvent"); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.i("test", "MyLinearLayout onInterceptTouchEvent"); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("test", "MyLinearLayout onTouchEvent"); return super.onTouchEvent(event); }}class MyButton extends Button { public MyButton(Context context) { super(context); } public MyButton(Context context, AttributeSet attrs) { super(context, attrs); } public MyButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.i("test", "MyButton dispatchTouchEvent"); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("test", "MyButton onTouchEvent"); return super.onTouchEvent(event); }}
代码很简单,就是一个Acitivity里面两个自定义控件,然后各自重写了方法,并打上log,下面是log:
这里就可以清楚的看见最先拿到事件的正是MainActivity,然后dispatch给LinearLayout,在传给button。这里处理了两个事件一个是按下一个是抬起。
但是这里肯定有人不明白,为什么在LinearLayout和Activity里都有onTouchEvent但是他们的log并没有打出来,这是为什么?其实,事件从产生到消费(处理)是经过了两次传递的。从事件的产生获取,然后传递叫事件传递,传到最后被一个view处理了,再返回处理结果,是处理顺序,假设Activity为A对象,LinearLayout为B对象,Button为C对象,那么事件分发顺序为:A——>B——>C,而事件的处理顺序正好反过来,应该是C——>B——>A。如下图:
上面类中重写的方法默认返回值分发过程是false,而处理过程默认为true;分发事件时返回值改为true表示拦截事件,不再往下传递;处理事件返回值改为false表示不处理了交给上级处理。而dispatchTouchEvent是分发的第一步一般不去修改。
下面做三个实验,把LinearLayout的onInterceptTouchEvent方法返回值改为true;把button的onTouchEvent返回值改为false;上面一步的基础上再把LinearLayout的onTouchEvent返回值改为false。分别看下log
正如上文所述,被LinearLayout拦截后,Button不会收到事件,LinearLayout自己处理事件,后面抬起事件就直接传给LinearLayout处理不进行拦截和传递操作。然后后面两个修改onTouchEvent也同理只是处理时的位置不同,道理就是最小的view不处理就往上抛,直到有onTouchEvent返回为true的地方再进行处理。
ok,码了半天。事件分发应该差不多就这些东西,欢迎指正~
- android事件分发机制
- Android事件分发机制
- Android 事件分发机制
- Android事件分发机制
- Android 事件分发机制
- Android 事件分发机制
- android 事件分发机制
- Android事件分发机制
- android 事件分发机制
- android事件分发机制
- Android 事件分发机制
- android事件分发机制
- android 事件分发机制
- android 事件分发机制
- Android 事件分发机制
- Android事件分发机制
- Android事件分发机制
- Android 事件分发机制
- 51Nod-1352-集合计数
- Statement和PreparedStatement的区别; 什么是SQL注入,怎么防止SQL注入?
- 跳出思维怪圈,其实你并没有多少选择。
- EasySwift/YXJKxMenu 微信,qq首页右上角的菜单效果
- EasySwift/EasyDropDownMenu 类似美团,糯米,大众点评的筛选排序菜单
- android事件分发机制
- 杭电acm1719
- cbp2make用法介绍
- 网格地图背景下的三种寻路算法
- 关于http socket timeout 超时时间 未设置 导致线程一直在等待(线程饥饿),微信公众号开发过程遇到的。java
- char数组和char*还有strcpy函数
- Java中的排序
- 手机号码、电话号码正则表达式
- logger-简介