简单分析View中的事件传递

首先是简单的创建一个项目,自定义两个ViewGroup,一个是RootViewGroup根节点,一个是中间层的MyViewGroup,还有一个自定义的MyView继承自Textview。
布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<dangyuan.jiuyang.com.myapplication.MyRootViewGroup
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="dangyuan.jiuyang.com.myapplication.MainActivity">

    <dangyuan.jiuyang.com.myapplication.MyViewGroup
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <dangyuan.jiuyang.com.myapplication.MyView
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </dangyuan.jiuyang.com.myapplication.MyViewGroup>

</dangyuan.jiuyang.com.myapplication.MyRootViewGroup>

1.所有都不改变,全部方法都是去super父类的方法,打印日志如下:

View: MyRootViewGroup-dispatchTouchEvent 默认情况下返回false。
View: MyRootViewGroup-onInterceptTouchEvent 默认情况下返回false。
View: MyViewGroup-dispatchTouchEvent
View: MyViewGroup-onInterceptTouchEvent
View: MyView-dispatchTouchEvent
View: MyView-onTouchEvent
View: MyViewGroup-onTouchEvent
View: MyRootViewGroup-onTouchEvent
View: MainActivity–onTouchEvent
层层递进的关系,先是最外层的viewgroup的dispatchTouchEvent进行分发,最后是activity中的onTouchEvent;

2.只更改MyRootViewGroup-dispatchTouchEvent,return改为true情况下:

View: MyRootViewGroup-dispatchTouchEvent — return true;
可以看到事件止步于第一个分发。所以一般情况下该方法不应该去擅自改动,它是真正在传递事件。

3.只更改MyRootViewGroup-dispatchTouchEvent,return改为false情况下:

View: MyRootViewGroup-dispatchTouchEvent — return false;
View: MainActivity–onTouchEvent
View: MainActivity–onTouchEvent
可以看到依然没有调用父类方法去传递事件,但是直接返回到了activity的onTouchEvent事件中。

4.只更改MyRootViewGroup-onInterceptTouchEvent,return改为true情况下:

View: MyRootViewGroup-dispatchTouchEvent
View: MyRootViewGroup-onInterceptTouchEvent — return true;
View: MyRootViewGroup-onTouchEvent
View: MainActivity–onTouchEvent
可以看到事件被拦截了,只在最外层的view中传递了一圈之后回到activity中结束。

5.只更改MyRootViewGroup-onTouchEvent return改为true情况下:

View: MyRootViewGroup-dispatchTouchEvent
View: MyRootViewGroup-onInterceptTouchEvent
View: MyViewGroup-dispatchTouchEvent
View: MyViewGroup-onInterceptTouchEvent
View: MyView-dispatchTouchEvent
View: MyView-onTouchEvent
View: MyViewGroup-onTouchEvent
View: MyRootViewGroup-onTouchEvent—-return true;
很显然,事件传递没有不同,只是最后不在调用activity中的onTouchEvent方法了,意味着该事件在MyRootViewGroup中已经被消费了,不需要传递了。

6.只更改MyViewGroup-dispatchTouchEvent,return改为true情况下:

View: MyRootViewGroup-dispatchTouchEvent
View: MyRootViewGroup-onInterceptTouchEvent
View: MyViewGroup-dispatchTouchEvent — return true;
View: MyRootViewGroup-dispatchTouchEvent
View: MyRootViewGroup-onInterceptTouchEvent
View: MyViewGroup-dispatchTouchEvent
还是上次的结论,dispatchTouchEvent方法不要轻易改动,中间的viewgroup改动return为true之后,事件就不再向下传递直接结束了。

7.更改MyViewGroup-onInterceptTouchEvent return改为true情况下:

View: MyRootViewGroup-dispatchTouchEvent
View: MyRootViewGroup-onInterceptTouchEvent
View: MyViewGroup-dispatchTouchEvent
View: MyViewGroup-onInterceptTouchEvent —-return true;
View: MyViewGroup-onTouchEvent
View: MyRootViewGroup-onTouchEvent
View: MainActivity–onTouchEvent
所以可以得出结论,某一层级的viewGroup的onInterceptTouchEvent —-return true时,它下一层级的子view或者viewgroup都将不会接收到事件,事件会在该层调用onTouchEvent之后直接返回上级的onTouchEvent方法,最终调用activity中的该方法。
所以,如果你想拦截某一事件的传递,需要在该层的viewgroup的onInterceptTouchEvent中return true。

8.只更改MyViewGroup-onTouchEvent return改为true情况下:

View: MyRootViewGroup-dispatchTouchEvent
View: MyRootViewGroup-onInterceptTouchEvent
View: MyViewGroup-dispatchTouchEvent
View: MyViewGroup-onInterceptTouchEvent
View: MyView-dispatchTouchEvent
View: MyView-onTouchEvent
View: MyViewGroup-onTouchEvent —-return true。
很显然,onTouchEvent return为true时就代表事件已经被消费,不需要也不可能再向上一层级的viewgroup和activity中的onTouchEvent传递了

9.只更改MyView–dispatchTouchEvent,return改为true情况下:

07-30 13:42:44.453 6413-6413/dangyuan.jiuyang.com.myapplication D/View: MyRootViewGroup-dispatchTouchEvent
07-30 13:42:44.453 6413-6413/dangyuan.jiuyang.com.myapplication D/View: MyRootViewGroup-onInterceptTouchEvent
07-30 13:42:44.453 6413-6413/dangyuan.jiuyang.com.myapplication D/View: MyViewGroup-dispatchTouchEvent
07-30 13:42:44.453 6413-6413/dangyuan.jiuyang.com.myapplication D/View: MyViewGroup-onInterceptTouchEvent
07-30 13:42:44.453 6413-6413/dangyuan.jiuyang.com.myapplication D/View: MyView-dispatchTouchEvent
所以,尽量不要改动dispatchTouchEvent方法,因为该方法承担着事件分配的任务,改为true会导致事件的戛然而止,后面不再进行传递处理

10.只更改MyView–onTouchEvent return改为true情况下。其实大胆猜测肯定也是运行到MyView–onTouchEvent就结束了事件的消费,打印日志也说明了这点:

View: MyRootViewGroup-dispatchTouchEvent
View: MyRootViewGroup-onInterceptTouchEvent
View: MyViewGroup-dispatchTouchEvent
View: MyViewGroup-onInterceptTouchEvent
View: MyView-dispatchTouchEvent
View: MyView-onTouchEvent —-return true。
很显然,onTouchEvent返回true就不会再去调用上一层级的onTouchEvent方法了。

打印日志很明显就可以得出事件传递的真正顺序:
dispatchTouchEvent方法是用来传递和分配事件的,一般不应该轻易改动,会造成事件传递的终止;onInterceptTouchEvent默认为false。即不拦截,如果为true,就会将事件拦截,直接调用到统一层级的onTouchEvent方法,然后再判断是否消费进行向上的传递,而它的子view或者viewGroup都不会接收到这一事件,因此onInterceptTouchEvent真正起到了事件的拦截作用;onTouchEvent是会事件的消费,如果返回true就不会向上一层传递过去,代表已经将该事件消费掉,如果都不消费,最终会传递到activity中。

猜你喜欢

转载自blog.csdn.net/m0_37194191/article/details/76382980