在项目中,经常遇到事件冲突,ScrollView,ViewPager滑动卡顿等情况,比如:onClick和onLongClick事件冲突,dispatchTouchEvent,onInterceptTouchEvent这些方法都有一个boolean返回值,不同返回值事件处理机制是不同的。

一:事件分发流程

1:现在有一个场景,用户长按button,我们希望只触发onLongClick,然而onClick事件也触发了.

android recyvlerView事件穿透 android 事件传递原理_移动开发

这种情况比如简单,直接在onLongClick返回true就可以解决了,返回true表示onLongClick消费了这次事件。

2:view 和 viewGroup的介绍

View是所有UI组件的基类(如:TextView,Button,ImageView),而 ViewGroup是容纳这些组件的容器(如:LinearLayout,ReltiveLayout),ViewGroup是View派生出来的.

view有dispatchTouchEvent,onTouchEvent这两个方法,ViewGroup多了一个onInterceptTouchEvent方法,此方法决定触发事件是自己处理,还是分发给下一个组件处理.

2:事件涉及到的常用方法

用户点击屏幕时,将触发viewGroup的dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);

3:方法返回值介绍

dispatchTouchEvent是处理触摸事件分发,事件(多数情况)是从Activity的dispatchTouchEvent开始的。执行super.dispatchTouchEvent(ev),事件向下分发。

onInterceptTouchEvent是ViewGroup提供的方法,默认返回false,返回true表示拦截,返回true后,由该类的onTouchEvent方法来执行

onTouchEvent是View中提供的方法,ViewGroup也有这个方法,view中不提供onInterceptTouchEvent。view中默认返回true,表示消费了这个事件。

二:举一个栗子

1  老板将一个任务分配给经理,经理将任务分配给员工去完成,员工完成后,将结果反馈给经理,经理将任务结果反馈给老板,这是默认流程。

 

android recyvlerView事件穿透 android 事件传递原理_ide_02

默认流程dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev),全部返回super.xxxxxxx

 

android recyvlerView事件穿透 android 事件传递原理_github_03

       

 

输出日志的结果


10-15 20:13:31.600 8716-8716/com.activity E/info: BossView  dispatchTouchEvent()   boss create task!10-15 20:13:31.600 8716-8716/com.activity E/info: BossView  onInterceptTouchEvent()  boss将task 分配给manager
10-15 20:13:31.600 8716-8716/com.activity I/info: ManagerView  经理让onInterceptTouchEvent决定任务由谁完成
10-15 20:13:31.600 8716-8716/com.activity I/info: ManagerView  onInterceptTouchEvent()经理接收到任务,将任务分配给员工
10-15 20:13:31.601 8716-8716/com.activity I/info: EmployeesView 员工开始工作.
10-15 20:13:31.601 8716-8716/com.activity I/info: EmployeesView 员工圆满完成任务.
10-15 20:13:31.602 8716-8716/com.activity I/info: ManagerView   onTouchEvent() 经理验收任务结果,并向老板报告
10-15 20:13:31.602 8716-8716/com.activity E/info: BossView  onTouchEvent()   工作已经完毕


 

2  老板将一个任务分配给经理,经理将任务分配给员工去完成,员工觉得难度大,无法完成(onTouchEvent返回true),由于老板没有接收到工作报告,会不停向经理分发任务(managerView的dispatchTouchEvent方法将不停被调用,员工的dispatchTouchEvent方法也会被继续调用)。

android recyvlerView事件穿透 android 事件传递原理_ui_04

输出日志:

android recyvlerView事件穿透 android 事件传递原理_github_05

3  老板将一个任务分配给经理,因为上一次任务,经理并未收到员工的工作报告,所以这次经理决定,自己的来本次完成,将事件直接消费(onInterceptTouchEvent返回true),不分给员工去做,让员工一边凉快去 。

android recyvlerView事件穿透 android 事件传递原理_github_06

日志输出:


10-15 22:11:26.877 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_DOWN10-15 22:11:26.878 22219-22219/com.activity E/info: BossView  dispatchTouchEvent()   boss create task!
10-15 22:11:26.879 22219-22219/com.activity E/info: BossView  onInterceptTouchEvent()  boss将task 分配给manager
10-15 22:11:26.879 22219-22219/com.activity I/info: ManagerView  经理让onInterceptTouchEvent决定任务由谁完成
10-15 22:11:26.879 22219-22219/com.activity I/info: ManagerView  onInterceptTouchEvent()经理接收到任务安排,员工做得不好,自己来做任务
10-15 22:11:26.879 22219-22219/com.activity I/info: ManagerView   onTouchEvent() 经理验收任务结果,并向老板报告
10-15 22:11:26.879 22219-22219/com.activity E/info: BossView  onTouchEvent()   工作已经完毕
10-15 22:11:26.886 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_MOVE
10-15 22:11:26.902 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_MOVE
10-15 22:11:26.912 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_MOVE
10-15 22:11:26.919 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_MOVE
10-15 22:11:26.921 22219-22219/com.activity I/info: MainActivity--dispatchTouchEvent()ACTION_UP


三:代码

由于代码差不多,这里只贴出ManagerView的代码,完整代码下载连接在文章下方


public class ManagerView extends LinearLayout {
    private final String TAG="ManagerView  ";
    private int index=0;
    public ManagerView(Context context) {
        super(context);
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(index==0){
            Log.i("info",TAG+" onTouchEvent() 经理验收任务结果,并向老板报告");
        }else{
            Log.i("info",TAG+" onTouchEvent()  自己亲自来完成任务");
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        index = 0;
//        if(index==0){
//            Log.i("info",TAG+"onInterceptTouchEvent()经理接收到任务,将任务分配给员工");
//            return super.onInterceptTouchEvent(ev);
//        }else{
            Log.i("info",TAG+"onInterceptTouchEvent()经理接收到任务安排,员工做得不好,自己来做任务");
            return true;
//        }

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i("info",TAG+"经理让onInterceptTouchEvent决定任务由谁完成");
        return super.dispatchTouchEvent(ev);
    }
}

 

 

备注:上传代码时,我电脑github出了点小问题,如果代码有问题,请留言,代码下载地址:github