android事件分发那些事~

    xiaoxiao2026-03-26  11

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


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

    3个自定义ViewGroup(ViewGroup1,ViewGroup2,ViewGroup3),看到自定义别慌,就是继承下ViewGroup,就这么粗暴.1个自定义View,和上面一样粗暴.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

    转载请注明原文地址: https://ju.6miu.com/read-1308203.html
    最新回复(0)