android事件分发那些事~

来源:互联网 发布:淘宝服装品牌排行榜 编辑:程序博客网 时间:2024/05/15 07:58

百度”android事件分发”一堆文章,都是围绕dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent三个方法开始讨论源码的,看书也很难理解,而且容易忘记,尤其一些理论的,所以今天我们不分析源码,简单粗暴的动手实践去探索下它.


首先我们需要准备一些东西:

  1. 3个自定义ViewGroup(ViewGroup1,ViewGroup2,ViewGroup3),看到自定义别慌,就是继承下ViewGroup,就这么粗暴.
  2. 1个自定义View,和上面一样粗暴.
  3. 1个Activity,自动生成就行,只需要改下xml布局.
    ps:这里我多说一句,这里用RelativeLayout,LinearLayout什么的都是可以的,反正它们的爸爸都是ViewGroup,ViewGroup的爸爸是View,自定义是为了重写dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent从而打印日志,方便我们观察,不过自定义View没有onInterceptTouchEvent方法.

下面来布局我们的xml布局,就是叠罗汉式的,从下到上依次是ViewGroup1,ViewGroup2,ViewGroup3,View.
这里写图片描述

代码(这里是ViewGroup1的代码,其他的改改日志就好):

    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        int action = ev.getAction();        switch (action) {            case MotionEvent.ACTION_DOWN:                Log.e("Debug", "MyViewGroup1:dispatchTouchEvent ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("Debug", "MyViewGroup1:dispatchTouchEvent ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("Debug", "MyViewGroup1:dispatchTouchEvent ACTION_UP");                break;            default:                break;        }        boolean dispatchTouchEvent = super.dispatchTouchEvent(ev);        Log.e("Debug", "MyViewGroup1:super.dispatchTouchEvent(ev)" + dispatchTouchEvent);        return dispatchTouchEvent;    }    @Override    public boolean onInterceptTouchEvent(MotionEvent event) {        int action = event.getAction();        switch (action) {            case MotionEvent.ACTION_DOWN:                Log.e("Debug", "MyViewGroup1:onInterceptTouchEvent ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("Debug", "MyViewGroup1:onInterceptTouchEvent ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("Debug", "MyViewGroup1:onInterceptTouchEvent ACTION_UP");                break;            default:                break;        }        boolean onInterceptTouchEvent = super.onInterceptTouchEvent(event);        Log.e("Debug", "MyViewGroup1:super.onInterceptTouchEvent(event)" + onInterceptTouchEvent);        return onInterceptTouchEvent;    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        switch (action) {            case MotionEvent.ACTION_DOWN:                Log.e("Debug", "MyViewGroup1:onTouchEvent ACTION_DOWN");                break;            case MotionEvent.ACTION_MOVE:                Log.e("Debug", "MyViewGroup1:onTouchEvent ACTION_MOVE");                break;            case MotionEvent.ACTION_UP:                Log.e("Debug", "MyViewGroup1:onTouchEvent ACTION_UP");                break;            default:                break;        }        boolean onTouchEvent = super.onTouchEvent(event);        Log.e("Debug", "MyViewGroup1:super.onTouchEvent(event)" + onTouchEvent);        return onTouchEvent;    }

布局文件(这里注意下,MyView里需要添加android:clickable=”true”,自定义view默认是不可点击的,button这类的默认是可以点击的)

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <com.wjy.app.test.MyViewGroup1        android:layout_width="match_parent"        android:layout_height="match_parent">        <com.wjy.app.test.MyViewGroup2            android:layout_width="match_parent"            android:layout_height="match_parent">            <com.wjy.app.test.MyViewGroup3                android:layout_width="match_parent"                android:layout_height="match_parent">                <com.wjy.app.test.MyView                    android:id="@+id/my_view"                    android:layout_width="300dp"                    android:layout_height="300dp"                    android:background="@android:color/holo_blue_bright"                    android:clickable="true" />            </com.wjy.app.test.MyViewGroup3>        </com.wjy.app.test.MyViewGroup2>    </com.wjy.app.test.MyViewGroup1></RelativeLayout>

测试还有三十秒到达战场,碾碎它们.一顿控制变量法操作,操作的就是三个方法的boolean返回值,然后我们轻轻的点击MyView.

dispatchTouchEvent方法

E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup2:dispatchTouchEvent ACTION_DOWNE/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_DOWNE/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup3:dispatchTouchEvent ACTION_DOWNE/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_DOWNE/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)falseE/Debug: MyView:dispatchTouchEvent ACTION_DOWNE/Debug: MyView:onTouchEvent ACTION_DOWNE/Debug: MyView:super.onTouchEvent(event)trueE/Debug: MyView:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:dispatchTouchEvent ACTION_MOVEE/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_MOVEE/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup2:dispatchTouchEvent ACTION_MOVEE/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_MOVEE/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup3:dispatchTouchEvent ACTION_MOVEE/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_MOVEE/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)falseE/Debug: MyView:dispatchTouchEvent ACTION_MOVEE/Debug: MyView:onTouchEvent ACTION_MOVEE/Debug: MyView:super.onTouchEvent(event)trueE/Debug: MyView:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:dispatchTouchEvent ACTION_UPE/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_UPE/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup2:dispatchTouchEvent ACTION_UPE/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_UPE/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup3:dispatchTouchEvent ACTION_UPE/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_UPE/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)falseE/Debug: MyView:dispatchTouchEvent ACTION_UPE/Debug: MyView:onTouchEvent ACTION_UPE/Debug: MyView:super.onTouchEvent(event)trueE/Debug: MyView:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true

结论: Android事件分发顺序是先到ViewGroup层,在传递到View层(如上图从最底层开始传递)。

onInterceptTouchEvent方法

//ViewGroup1 中 onInterceptTouchEvent返回trueE/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:onTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:super.onTouchEvent(event)falseE/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)false//ViewGroup2 中 onInterceptTouchEvent返回trueE/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup2:dispatchTouchEvent ACTION_DOWNE/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_DOWNE/Debug: MyViewGroup2:onTouchEvent ACTION_DOWNE/Debug: MyViewGroup2:super.onTouchEvent(event)falseE/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)falseE/Debug: MyViewGroup1:onTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:super.onTouchEvent(event)falseE/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)false

结论:在ViewGroup中onInterceptTouchEvent方法对事件传递进行拦截,返回值true代表不允许事件继续向子View传递,反之继续传递。

onTouchEvent方法

//MyView 中 onTouchEvent 返回 trueE/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWNE/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup2:dispatchTouchEvent ACTION_DOWNE/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_DOWNE/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup3:dispatchTouchEvent ACTION_DOWNE/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_DOWNE/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)falseE/Debug: MyView:dispatchTouchEvent ACTION_DOWNE/Debug: MyView:onTouchEvent ACTION_DOWNE/Debug: MyView:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:dispatchTouchEvent ACTION_MOVEE/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_MOVEE/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup2:dispatchTouchEvent ACTION_MOVEE/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_MOVEE/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup3:dispatchTouchEvent ACTION_MOVEE/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_MOVEE/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)falseE/Debug: MyView:dispatchTouchEvent ACTION_MOVEE/Debug: MyView:onTouchEvent ACTION_MOVEE/Debug: MyView:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:dispatchTouchEvent ACTION_UPE/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_UPE/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup2:dispatchTouchEvent ACTION_UPE/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_UPE/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)falseE/Debug: MyViewGroup3:dispatchTouchEvent ACTION_UPE/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_UPE/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)falseE/Debug: MyView:dispatchTouchEvent ACTION_UPE/Debug: MyView:onTouchEvent ACTION_UPE/Debug: MyView:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)trueE/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true

结论:如果这里把ViewGroup1或者2的onTouchEvent方法返回true,打印出来和上面的日志是一样的,why?这里需要借助源码解释了,只要被view消耗了onTouchEvent事件,那么ViewGroup将无法收到该事件.

眼过千遍不如手过一遍,看再多的理论自己实践才是王道.
小弟的功力有限,这里推荐郭霖大神分析源码地址:http://blog.csdn.net/guolin_blog/article/details/9097463

1 0
原创粉丝点击