Android中事件处理机制一分钟理清思路

来源:互联网 发布:windows bat 相对路径 编辑:程序博客网 时间:2024/06/06 18:17


刚开始对我事件处理机制的概念还挺模糊的,而网上的讲解又很杂很乱.那么现在在这里你可以快速理清事件处理机制了.


首先用处肯定得知道:

事件处理机制就是为了应对嵌套式的布局中强焦点和弱焦点的点击事件进行自我定义。可以说是Android软件设计中重要的技术设计方法。

当然如果你想问嵌套式布局是什么?

嵌套式布局就如下图:一个界面中有父view,子view和子控件,但是点击事件的处理方案就可以通过事件处理机制来区分开来了


怎么使用:

ViewGroup的相关事件有三个:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。View的相关事件只有两个:dispatchTouchEvent、onTouchEvent。

代码详解(更清晰明了):

dispatchTouchEvent  true   dispatch直接消费
(往前一层)        false传递给上层ontouch
super.dispatchTouchEvent(ev)分发当前对象的intercept

onInterceptTouchEvent true  交给当前view的ontouch处理
false   交给子view的分发
super.dispatchTouchEvent(ev)  同false


onTouchEvent true接收并消费
false 由上层ontouch接收
super.dispatchTouchEvent(ev)同false

代码如下:

public class AView extends RelativeLayout {    public AView(Context context) {        super(context);    }    public AView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public AView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        System.out.println("AView.dispatchTouchEvent"+"A分发"+" 默认分发给拦截");        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        System.out.println("AView.onInterceptTouchEvent"+"  A拦截"+" false不拦截");        return false;    }    @Override    public boolean onTouchEvent(MotionEvent event) {        System.out.println("AView.onTouchEvent"+"  A消费"+" false不消费");        return false;    }}
B视图

public class BView extends RelativeLayout {    public BView(Context context) {        super(context);    }    public BView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public BView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        System.out.println("BView.dispatchTouchEvent"+"  B分发"+" 默认分发给拦截");        return super.dispatchTouchEvent(ev); //为了往下一层走    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        System.out.println("BView.onInterceptTouchEvent"+"  B拦截"+"false不拦截");        return false;    }    @Override    public boolean onTouchEvent(MotionEvent event) {        System.out.println("BView.onTouchEvent"+"  B消费"+"false不消费");        return false;    }

c子控件

public class CView extends TextView {    public CView(Context context) {        super(context);    }    public CView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public CView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        System.out.println("CView.onTouchEvent"+"  C消费"+"TextVeiw消费结束");        return true;    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        System.out.println("CView.dispatchTouchEvent"+"  C分发"+"直接给touch");        return onTouchEvent(ev); //直接传递给消费    }}

xml布局:

<?xml version="1.0" encoding="utf-8"?><com.example.lsh.shijianchuli.AView    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"    tools:context="com.example.lsh.shijianchuli.MainActivity">    <com.example.lsh.shijianchuli.BView        android:layout_width="300dp"        android:layout_height="300dp"        android:background="#f00"        >        <com.example.lsh.shijianchuli.CView            android:layout_width="100dp"            android:layout_height="100dp"            android:background="#ff0"            android:text="事件处理的text子控件"/>    </com.example.lsh.shijianchuli.BView></com.example.lsh.shijianchuli.AView>
结果如下图:
分析:这是为了将所有都view都分发到的形式,可以在中间直接拦截消费。子控件可能在布局中有很多个,并且子控件无法重写拦截,所以不会只执行一遍。
A.onInterceptTouchEvent-->B.onInterceptTouchEvent-->C.touchEvent(最深的子视图没重写onInterceptTouchEvent)-->C.touchEvent-->B.touchEvent-->A.touchEvent.也就是说拦截事件是父视图优先有子视图进行拦截,处理事件是子视图优先父视图进行处理。
注意点:

如果在A的分发为true,意味着父view的上一层(但是并没有),实际会以遍历来回的形式的形式执行六次dispatchTouchEventA分发,三个view往返两次。



工程结构图:



1 0