Anroid触摸事件分发流程dispatchTouchEvent(),onInterceptTouchEvent(),onTouchEvent()。

Android触摸事件的分发机制是学习自定义控件的过程中必须理清的知识点。今天我们就讲一下Android的触摸事件分发的全过程。

首先引进一个列子

<?xml version="1.0" encoding="utf-8"?>
<test.weizhong.com.customviewtest.ViewGroupBottom xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#256845"
    tools:context="test.weizhong.com.customviewtest.Main2Activity">


    <test.weizhong.com.customviewtest.ViewGroupMiddle
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="46dp"
        android:background="#668416">


        <test.weizhong.com.customviewtest.ViewGroupTop
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="46dp"
            android:background="#B48521"/>


    </test.weizhong.com.customviewtest.ViewGroupMiddle>


</test.weizhong.com.customviewtest.ViewGroupBottom>
我们先写一个三层嵌套的布局,并且为每一层设置不同颜色,以便于点击的时候能区分自己点击了哪一层。
然后我们在每一层的布局里面为dispatchTouchEvent(),onInterceptTouchEvent(),onTouchEvent()打一个log,
来观察方法的调用顺序。
public class ViewGroupBottom extends LinearLayout{


    public ViewGroupBottom(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean t = super.dispatchTouchEvent(ev);
        Log.e("TAG","ViewGroupBottom : dispatchTouchEvent() == " + t);
        return t;
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean t = super.onInterceptTouchEvent(ev);
        Log.e("TAG","ViewGroupBottom : onInterceptTouchEvent() == " + t);
        return t;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean t = super.onTouchEvent(event);
        Log.e("TAG","ViewGroupBottom : onTouchEvent() == " + t);
        return t;
    }
}


public class ViewGroupMiddle extends LinearLayout{


    public ViewGroupMiddle(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean t = super.dispatchTouchEvent(ev);
        Log.e("TAG","ViewGroupMiddle : dispatchTouchEvent() == " + t);
        return t;
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean t = super.onInterceptTouchEvent(ev);
        Log.e("TAG","ViewGroupMiddle : onInterceptTouchEvent() == " + t);
        return t;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean t = super.onTouchEvent(event);
        Log.e("TAG","ViewGroupMiddle : onTouchEvent() == " + t);
        return t;
    }
}


public class ViewGroupTop extends LinearLayout{


    public ViewGroupTop(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean t = super.dispatchTouchEvent(ev);
        Log.e("TAG","ViewGroupTop : dispatchTouchEvent() == " + t);
        return t;
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean t = super.onInterceptTouchEvent(ev);
        Log.e("TAG","ViewGroupTop : onInterceptTouchEvent() == " + t);
        return t;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean t = super.onTouchEvent(event);
        Log.e("TAG","ViewGroupTop : onTouchEvent() == " + t);
        return t;
    }
}






首先点击ViewGroupTop
12-14 13:58:34.943 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : onInterceptTouchEvent() == false
12-14 13:58:34.943 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : onInterceptTouchEvent() == false
12-14 13:58:34.943 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupTop : onInterceptTouchEvent() == false
12-14 13:58:34.943 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupTop : onTouchEvent() == false
12-14 13:58:34.943 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupTop : dispatchTouchEvent() == false
12-14 13:58:34.943 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : onTouchEvent() == false
12-14 13:58:34.943 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : dispatchTouchEvent() == false
12-14 13:58:34.943 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : onTouchEvent() == false
12-14 13:58:34.943 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : dispatchTouchEvent() == false


我们发现在默认情况下先调用了ViewGroupBottom 的onInterceptTouchEvent(),然后是ViewGroupMiddle的onInterceptTouchEvent()
最后是ViewGroupTop 的 onInterceptTouchEvent(),onTouchEvent()。


我们再点击ViewGroupMiddle


12-14 14:03:09.813 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : onInterceptTouchEvent() == false
12-14 14:03:09.813 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : onInterceptTouchEvent() == false
12-14 14:03:09.813 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : onTouchEvent() == false
12-14 14:03:09.813 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : dispatchTouchEvent() == false
12-14 14:03:09.813 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : onTouchEvent() == false
12-14 14:03:09.813 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : dispatchTouchEvent() == false
发现触摸事件只传递到ViewGroupMiddle,就调用了ViewGroupMiddle的onTouchEvent()了。


所以我们得出了触摸事件的传递方向  1、触摸事件是由布局的根部往子控件传递的,而且只传递到你点击的那一层子布局。




接下来我们修改ViewGroupMiddle的onInterceptTouchEvent的返回值为true,再点击ViewGroupTop。
@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean t = super.onInterceptTouchEvent(ev);
        Log.e("TAG","ViewGroupMiddle : onInterceptTouchEvent() == " + t);
        return true;
    }

12-14 14:09:49.633 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : onInterceptTouchEvent() == false
12-14 14:09:49.633 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : onInterceptTouchEvent() == false
12-14 14:09:49.633 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : onTouchEvent() == false
12-14 14:09:49.633 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : dispatchTouchEvent() == false
12-14 14:09:49.633 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : onTouchEvent() == false
12-14 14:09:49.633 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : dispatchTouchEvent() == false


我们发现触摸事件从ViewGroupBottom传递到了ViewGroupMiddle,但是并没有传递到ViewGroupTop。而是又调用了ViewGroupMiddle的
onTouchEvent(),和dispatchTouchEvent()。所以onInterceptTouchEvent()设置为true是阻断触摸事件往子控件传递的。阻断了之后就
调用自己的onTouchEvent()来处理事件,并且在处理完事件之后调用dispatchTouchEvent()来上报父控件我是否处理了该事件。那么
我们要上报给父控件什么值,又会产生什么效果呢?
我们刚才的ViewGroupMiddle里面dispatchTouchEvent()返回的是默认值,也就是false,父控件则调用了onTouchEvent() 和
dispatchTouchEvent()来回应。如果我们把ViewGroupMiddle里面dispatchTouchEvent()的返回值改为true呢?又有什么效果?
我们来试一下,把ViewGroupMiddle里面dispatchTouchEvent()的返回值改为true,并且点击ViewGroupTop


12-14 14:22:33.363 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : onInterceptTouchEvent() == false
12-14 14:22:33.363 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : onInterceptTouchEvent() == false
12-14 14:22:33.363 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : onTouchEvent() == false
12-14 14:22:33.363 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupMiddle : dispatchTouchEvent() == false
12-14 14:22:33.363 30747-30747/test.weizhong.com.customviewtest E/TAG: ViewGroupBottom : dispatchTouchEvent() == true
我们发现把ViewGroupMiddle里面dispatchTouchEvent()的返回值改为true之后父控件ViewGroupBottom的onTouchEvent()方法不再调用了。
这是为什么呢?原来子控件返回的dispatchTouchEvent()值对父控件产生了影响。


由此我们可以假设触摸事件的传递过程是,父控件传递触摸事件过来之后,我们可以通过onInterceptTouchEvent()的返回值来告诉
子控件我要不要处理这个事件,如果我要处理这个事件则调用onTouchEvent(),在onTouchEvent()里面处理,子控件就不必接收该
事件了。处理完了事件之后又通过dispatchTouchEvent()的返回值告诉父控件我是否处理好了,如果处理好了就返回true,让父控件
再向上告知我已经处理完了就可以了,父控件就不必要处理了。如果我没处理好则返回false,告知父控件并让父控件去处理。总之
每一级的控件重复这样的逻辑。





所以,其实触摸事件的传递就像是一个公司的任务分配流程一样。比如老板有一个需求,他告知项目经理,项目经理如果觉得这个
事情只能由他来做,那么他自己就做了,不再通知下属。当他做完了就直接反馈给老板说我做完了。如果他最终没做好,就通知
老板说我没做好,由老板自己再去想办法做。
如果项目经理觉得他自己做不了,但是他的下属程序猿能做,那么他就会把事件传递给程序猿。程序猿再根据自己的情况自己去处理。




































































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闽农qq:994955138

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值