View事件处理机制
来源:互联网 发布:特许网络的组织结构 编辑:程序博客网 时间:2024/06/05 09:56
View事件处理机制
在View中有两个对象可以对touch事件进行处理,分别是OnTouchListener和OnClickListener(包含OnLongClickListener),当View被touch时,该View的父容器会调用View的 boolean dispatchTouchEvent(MotionEvent event)方法,即View处理touch事件的入口。根据OnTouchListener和OnClickListener是否存在可以将touch处理分为四种情况: T空,C空:dispatchTouchEvent()返回false; T空,C不为空:返回true; T不为空,C空:如果T return false 则 dispatchTouchEvent() 返回false;false 则false; T、C都不为空:T return true 则不执行C,返回true;T return false 则执行C并且返回true。
也就是说只要C不为空则返回true,T存在且return true 则不执行C并且返回true。
ViewGroup事件处理机制
ViewGroup继承并重写了boolean dispatchTouchEvent(MotionEvent event)方法。ViewGroup处理touch事件的逻辑有点类似与链表。从父容器一直往下传递。在Event.down事件时,父容器会保存处理了touch事件的下一级容器的引用,如果没有子容器处理则,调用自身super.dispatchTouchEvent(MotionEvent event)处理。也可以重写onInterceptTouchEvent(ev) return true 拦截处理。
综合案例分析
以下摘自:http://www.longdw.com/android-onintercepttouchevent-ontouchevent/
源码:
[java] view plaincopy
public class MainActivity extends Activity {
Group1 group1;
Group2 group2;
MyTextView myTv;
/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //--group1 //----| //-------group2 //---------| //------------myTv group1 = new Group1(this); group2 = new Group2(this); myTv = new MyTextView(this); group2.addView(myTv, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); group1.addView(group2, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); setContentView(group1); }
}
[java] view plaincopy
public class Group1 extends FrameLayout {
public Group1(Context context) { super(context); // TODO Auto-generated constructor stub } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "Group1 onInterceptTouchEvent触发事件:"+Constant.getActionTAG(ev.getAction())); return false; } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "Group1 onTouchEvent触发事件:"+Constant.getActionTAG(event.getAction())); return false; }
}
[java] view plaincopy
public class Group2 extends FrameLayout {
public Group2(Context context) { super(context); // TODO Auto-generated constructor stub } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "Group2 onInterceptTouchEvent触发事件:"+Constant.getActionTAG(ev.getAction())); return false; } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "Group2 onTouchEvent触发事件:"+Constant.getActionTAG(event.getAction())); return false; }
}
[java] view plaincopy
public class MyTextView extends TextView {
public MyTextView(Context context) { super(context); this.setGravity(Gravity.CENTER); this.setText("点击我!"); // TODO Auto-generated constructor stub } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "MyTextView onTouchEvent触发事件:"+Constant.getActionTAG(event.getAction())); return false; }
}
[java] view plaincopy
public class Constant {
public static final String LOGCAT = “logcat”;
public static String getActionTAG(int action) { switch (action) { case 0: return "ACTION_DOWN"; case 1: return "ACTION_UP"; case 2: return "ACTION_MOVE"; default: return "NULL"; } }
}
分别重写Group1和Group2的onInterceptTouchEvent和onTouchEvent方法,重写MyTextView的onTouchEvent方法,最终得到的控件层次结构如下:
1.在默认返回值情况下logcat输出如下:
测试后可知默认情况下和所有方法返回值为false的结果一致,down事件的捕获顺序onInterceptTouchEvent先于onTouchEvent,由于onTouchEvent返回值为false,down事件没被消化,后续的move和up事件没有出现,同时逆序返回到父控件的onTouchEvent方法来捕获,如下图所示:
2.所有onTouchEvent返回值为true情况下logcat输出如下:
输出结果可以看出子控件MyTextView消化了down事件,后续的move和up事件正常捕获,由于down事件被消化,上层的onTouchEvent方法不执行,如下图所示:(三箭头分别指down、move、up事件)
既然如此,如果MyTextView中onTouchEvent方法返回为false,而group1和group2的onTouchEvent方法返回true的结果自然也就如下图的顺序了:
测试输出结果证明了这一猜测顺序:
注意:可能有人对这种情况比较疑惑,ACTION_DOWN还好理解,但是ACTION_MOVE为什么没有经历myTv,而且ACTION_MOVE只经历了group1的onInterceptTouchEvent和group2的onTouchEvent而没有经历group2的onInterceptTouchEvent?我开始也费解,后来想想也是,大家对比第1条,由于onTouchEvent返回了false而没有消耗down事件导致后续的move和up都没有出现,这里也是一样由于myTv中onTouchEvent返回了false也就是说没有消耗down事件,那么后面的move和up也都不会出在这个view里面,但是group2截获到了down事件,但后来的move为什么group2中的onInterceptTouchEvent没有执行到呢,原因大家不要忘记了onInterceptTouchEvent的初衷是什么,返回false是让它的子view或viewgroup类处理,而group2的子控件显然是myTv而myTv的onTouchEvent返回了false也就是接收不到后续的move和up事件,也就没必要经过onInterceptTouchEvent来继续分发了(因为分发了也还是接收不到),经过group2的onTouchEvent因为它返回的是true,截获了事件并且消耗了事件。
3.当某个GroupView中的onInterceptTouchEvent方法返回值为true情况下logcat输出如下(如group2):
如果在该方法返回值中返回true,那么子控件将获取不到任何点击事件,转而向自身的onTouchEvent方法转发,如下图所示:
如果onTouchEvent方法返回值都为true,那么根据规律结果就如下图顺序触发:
最后logcat的结果证实了这一猜测:
还有一篇文章也比较好,可作为这个案例的补充,http://orgcent.com/android-touch-event-mechanism/
- View事件处理机制
- View事件处理机制
- View的事件处理机制
- View的事件处理机制
- Android-View事件处理机制
- view事件的处理机制
- View Touch事件处理机制
- view、viewgroup 事件响应拦截处理机制
- View机制深入学习(五) 事件处理机制一
- view的事件的处理机制-源码分析
- android view、viewgroup 事件响应拦截处理机制
- view 事件分发机制
- View 事件分发机制
- View事件传递机制
- View事件分发机制
- view事件机制
- view事件分发机制
- View 事件传递机制
- 介绍一个python的新的web framework——karloop框架
- 【密钥算法】Java加密技术(四)---RSA数据加密算法(2)
- C语言 数据及其数据类型
- Android自定义对话框实现QQ退出界面
- AsyncTask探究
- View事件处理机制
- 利用事件对象 实现线程同步
- 【密钥算法】Java加密技术(五)---DH 数据加密算法
- Typescript的类的使用
- 【密钥算法】Java加密技术(六)---DSA 数字签名算法
- C++对象的内存布局
- java设计模式之——代理模式
- 【密钥算法】Java加密技术(七)---ECC 数据加密算法
- 开贴搞航模