android事件分发那些事~

百度”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_DOWN
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_DOWN
E/Debug: MyView:onTouchEvent ACTION_DOWN
E/Debug: MyView:super.onTouchEvent(event)true
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true

E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_MOVE
E/Debug: MyView:onTouchEvent ACTION_MOVE
E/Debug: MyView:super.onTouchEvent(event)true
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true

E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_UP
E/Debug: MyView:onTouchEvent ACTION_UP
E/Debug: MyView:super.onTouchEvent(event)true
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true

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

onInterceptTouchEvent方法

//ViewGroup1 中 onInterceptTouchEvent返回true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:onTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onTouchEvent(event)false
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)false

//ViewGroup2 中 onInterceptTouchEvent返回true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:onTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:super.onTouchEvent(event)false
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)false
E/Debug: MyViewGroup1:onTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onTouchEvent(event)false
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)false

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

onTouchEvent方法

//MyView 中 onTouchEvent 返回 true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_DOWN
E/Debug: MyView:onTouchEvent ACTION_DOWN
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true

E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_MOVE
E/Debug: MyView:onTouchEvent ACTION_MOVE
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true

E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_UP
E/Debug: MyView:onTouchEvent ACTION_UP
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值