笔记 Androd 自定义控件学习(六)

说明:文章来自《Android群英传》学习笔记

事件拦截机制分析

当Android系统捕获到用户的各种输入事件后,如何准确地传递给真正需要这个事件的控件呢?Android给我们提供了一套完整的事件传递,处理机制,来帮助开发者完成准确的事件分配与处理。
关于触摸事件,大家都很清楚了,就不做解释。Android为触摸事件封装了一个类—MotionEvent,如果重写 onTouchEvent()方法,该函数的参数就是一个 MotionEvent。在 MotionEvent 里面封装了很多东西,比如触摸点的坐标,可以通过 event.getX()方法和event.getRawX()方法取出坐标点;在比如获取点击事件的类型,可以通过不同的Action(如 MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE,MotionEvent.ACTION_UP)来区分。并实现相应的逻辑。
我们知道Android的View结构是树形结构,也就是说,View可以放在ViewGroup里面,通过不同的组合来实现不同的样式,View放在一个ViewGroup里面,这个ViewGroup又放在另一个ViewGroup里面,这样多层嵌套,我们就一个触摸事件,这样子View和父ViewGroup都有可能想要处理这个事件,因此就产生了事件拦截(事件冲突)。
如图说明,我们定义一个事件案列:
这里写图片描述
底层 MyViewGroupA,MyViewGroupB 为两层嵌套的 LinearLayout 布局,MyView为自定义的View,我们在这三个类中重写事件分发的相关方法:dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent() 方法。

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        L.i("dispatchTouchEvent MyViewGroupA");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        L.i("onInterceptTouchEvent MyViewGroupA");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        L.i("onTouchEvent MyViewGroupA");
        return super.onTouchEvent(event);
    }

对于View来说,重写了如下所示的两个方法:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        L.i("dispatchTouchEvent MyView");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        L.i("onTouchEvent MyView");
        return super.onTouchEvent(event);
    }

从上面的代码中可以看到,ViewGroup级别比较高,比View多了一个方法onInterceptTouchEvent()。这个方法就是事件拦截的核心方法。我们执行程序,点击程序,看一下log日志:

customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: onInterceptTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: onInterceptTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyView
customview.android.com.intercepttouchevent_demo I/zdd: onTouchEvent MyView
customview.android.com.intercepttouchevent_demo I/zdd: onTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: onTouchEvent MyViewGroupA

可以看见,正常情况,事件的传递顺序是:
MyViewGroupA — MyViewGroupB —MyView 事件传递的时候,先执行dispatchTouchEvent(),在执行onInterceptTouchEvent()方法。
事件的处理顺序是放好反过来的。MyView — MyViewGroupB —MyViewGroupA
事件传递的返回值非常容易理解,也是重点:true(拦截时间),false(不拦截,继续下发事件)
时间处理的返回值也是类似,True(处理了事件,不在上报事件),false (继续上报事件,给父View处理事件)

这里我们通过图片理解事件拦截的过程 即onInterceptTouchEvent()方法和onTouchEvent 方法的处理过程:
这里写图片描述
可以看到,当MyViewGroupA的onInterceptTouchEvent() 方法 返回true时,事件就不会下发了,直接有MyViewGroupA的onTouchEvent()方法处理事件,log如下:

customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: onInterceptTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: onTouchEvent MyViewGroupA

当MyViewGroupA的onInterceptTouchEvent() 方法 返回 false 时,事件继续下发,到下一个View,而当MyViewGroupB的onInterceptTouchEvent() 方法 返回true时,事件也就不会下发了,直接有MyViewGroupB的onTouchEvent()方法处理事件,log如下:

customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: onInterceptTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: onInterceptTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: onTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: onTouchEvent MyViewGroupA

对于事件的处理,同样我们直接返回true,看一下log:
MyView 的 onTouchEvent () 方法返回true:

customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: onInterceptTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: onInterceptTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyView
customview.android.com.intercepttouchevent_demo I/zdd: onTouchEvent MyView

可以看到事件返回true时,事件就不上传了,同理我们MyView任然返回false,但是 MyViewGroupB的onTouchEvent 方法返回true;log如下:

customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: onInterceptTouchEvent MyViewGroupA
customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: onInterceptTouchEvent MyViewGroupB
customview.android.com.intercepttouchevent_demo I/zdd: dispatchTouchEvent MyView
customview.android.com.intercepttouchevent_demo I/zdd: onTouchEvent MyView
customview.android.com.intercepttouchevent_demo I/zdd: onTouchEvent MyViewGroupB

这样我们就初步了解了一下事件分发机制的流程。需要深入了解的可以去查看源码。

猜你喜欢

转载自blog.csdn.net/zhu522959034/article/details/80857859
今日推荐