流程Android知识Android开发

大话android事件传递机制

2016-09-09  本文已影响428人  码无止境

背景

看了很多关于android事件传递的技术博客,写得特别官方,不接地气,让人看了以后不是特别深刻。特别在遇到一些滑动冲突问题上面,不知道如何去解决,大概知道有dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent三个方法可以解决问题,然后尝试着一个一个return ture or false解决问题,虽然运气好解决了问题,但为何是那样?却一知半解。

目的

通俗易懂地帮助大家去理解android事件传递机制,能举一反三地解决事件传递相关的疑难杂点。

主题

今日笔者带领大家从代码的角度去分析android事件传递机制,解开大家心里的疑惑。大家从各种技术渠道都大致了解了事件传递机制有两大主角,分别是ViewGroup、View。然后会有童鞋会问,那activity呢?其实activity可归类ViewGroup。在事件传递机制中,了解过事件传递的童鞋应该知道ViewGroup有三个方法分别对应:分发事件(dispatchTouchEvent)、拦截事件(onInterceptTouchEvent)、消费事件(onTouchEvent);View只有两个方法,跟ViewGroup区别,就少了一个拦截事件(onInterceptTouchEvent)。

分发事件(dispatchTouchEvent)

拦截事件(onInterceptTouchEvent)

消费事件(onTouchEvent)

接下来我们开始从代码的角度分析android事件传递机制,首先我们创建一个自定义ViewGroup和一个自定义View,分别为CustomLayout、CustomView。
CustomLayout可用对应代码如下:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        System.out.println("dddddddddddddddddd CustomLayout dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        System.out.println("dddddddddddddddddd CustomLayout onInterceptTouchEvent");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // CustomButton onTouchEvent
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                System.out.println("ddddddddddddddddddddd CustomLayout onTouchEvent ACTION_DOWN");
                return true;
            case MotionEvent.ACTION_UP:
                System.out.println("ddddddddddddddddddddd CustomLayout onTouchEvent ACTION_UP");
                break;
        }
        System.out.println("ddddddddddddddddddddd CustomLayout onTouchEvent(event) = " + super.onTouchEvent(event));
        return super.onTouchEvent(event);
    }

CustomView可用对应代码如下:

  @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        System.out.println("dddddddddddddddddd CustomView dispatchTouchEvent");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                System.out.println("ddddddddddddddddddddd CustomView onTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_UP:
                System.out.println("ddddddddddddddddddddd CustomView onTouchEvent ACTION_UP");
                break;
        }
        System.out.println("ddddddddddddddddddddd CustomView onTouchEvent(event) = " + super.onTouchEvent(event));
        return super.onTouchEvent(event);
    }

然后app run起来,结果如下:

09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout dispatchTouchEvent
09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout onInterceptTouchEvent
09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomView dispatchTouchEvent
09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent ACTION_DOWN
09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent(event) = false
09-09 10:45:42.411 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomLayout onTouchEvent ACTION_DOWN
09-09 10:45:42.458 3011-3011/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout dispatchTouchEvent
09-09 10:45:42.458 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomLayout onTouchEvent ACTION_UP
09-09 10:45:42.458 3011-3011/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomLayout onTouchEvent(event) = false

我们发现最先执行的是ViewGroup里面的dispatchTouchEvent(事件分发)方法,然后onInterceptTouchEvent(事件拦截),ViewGroup未拦截,就将事件传递给了View,执行了View的dispatchTouchEvent(事件分发)方法,接着是View的onTouchEvent事件,而View的onTouchEvent事件中最先执行的是ACTION_DOWN方法,然后发现View的onTouchEvent事件并没有消费事件(类似没有完成任务),就将该事件又传回给了ViewGroup,此时执行 ViewGroup的onTouchEvent事件,然后ViewGroup重新分发事件,这时没有把事件给View,而是直接执行了ViewGroup的onTouchEvent事件,然而自己也未消费该事件,该事件会继续往上传,依次类推。

此时如果我们将View中ACTION_DOWN事件给返回true,结果会如何呢?请看下面:

09-09 10:59:16.228 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout dispatchTouchEvent
09-09 10:59:16.228 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout onInterceptTouchEvent
09-09 10:59:16.228 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomView dispatchTouchEvent
09-09 10:59:16.228 10636-10636/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent ACTION_DOWN
09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout dispatchTouchEvent
09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomLayout onInterceptTouchEvent
09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: dddddddddddddddddd CustomView dispatchTouchEvent
09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent ACTION_UP
09-09 10:59:16.265 10636-10636/cn.jianke.eventdistributiondemo I/System.out: ddddddddddddddddddddd CustomView onTouchEvent(event) = false

从上面结果可知,当在View中onTouch ACTION_DOWN动作消费了onTouch事件,当执行ACTION_UP动作,事件依然会将事件分发给View处理。

根据上面结果做个总结,ViewGroup类似领导,View类似下属,事件类似工作任务,领导给下属分配工作任务,如果下属能按时完成工作任务,那么领导下次安排工作任务时,就会将工作任务继续分发给该下属,否者就领导看自己能否处理该工作任务,不能处理就直接把工作任务反馈给他的直接上司,依次类推。

扩展

这里进行一下扩展,onTouch跟onClick有啥关系?也许有童鞋会思考这个问题。当onTouch action为ACTION_DOWN时,如果返回ture(直接消费了该事件,类似下属处理了动作为ACTION_DOWN的工作,则不会再触发onClick事件和onLongClick事件)。

看了这篇文章,童鞋们是不是对android事件传递有了彻底的理解呢?

如有疑问,请留言。

关于作者

上一篇下一篇

猜你喜欢

热点阅读