Android中的事件分发

对象
  • Activity
  • View
  • ViewGroup
内容
  • dispatchTouchEvent()
  • onInterceptTouchEvent()
  • onTouchEvent()

在Android 中,视图的概念其实就是View,存放由多个View组成的视图组的载体就是ViewGroup,最后把视图或者视图组的呈现给使用者的载体,就是大家所熟悉的Activity。然而在当下触屏的电子产品时代,对于一个Android开发者而言,触碰事件的基础也将不在仅仅是基础了。

  • dispatchTouchEvent:处理触碰事件的分发,执行super.dispatchTouchEvent(ev),事件向下分发。
  • onInterceptTouchEvent:ViewGroup提供的方法,默认返回false,返回true表示拦截。
  • onTouchEvent:默认返回true,表示消费了这个事件。

Activity里,有两个回调函数

public boolean dispatchTouchEvent(MotionEvent ev);    
public boolean onTouchEvent(MotionEvent event);
 

View里,有两个回调函数

public boolean dispatchTouchEvent(MotionEvent ev);    
public boolean onTouchEvent(MotionEvent event);
 

ViewGroup里,有三个回调函数

public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onInterceptTouchEvent(MotionEvent ev);     
public boolean onTouchEvent(MotionEvent event);
 

Activity

Android中通常点击事件用MotionEvent来表示,当一个点击操作发生时,事件最先传递给当前的Activity,由Activity的dispatchTouchEvent来进行事件的分发,具体工作是由Activity内部的Window来完成的。Window会将事件传递给decorview,decorview一般就是当前界面的底层容器(即setContentView所设置的View的父容器),通过Activity.getWindow.getDecorView()可以获得。关于Activity事件分发机制的源码,我们重点来看下dispatchTouchEvent和onTouchEvent方法。
dispatchTouchEvent

实现类Activity的dispatchTouchEvent方法,用来做Log信息跟踪:
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        String motionEventInfo = "";
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                motionEventInfo = "ACTION_DOWN";
                break;
            case MotionEvent.ACTION_MOVE:
                motionEventInfo = "ACTION_MOVE";
                break;
            case MotionEvent.ACTION_UP:
                motionEventInfo = "ACTION_UP";
                break;
            default:
                motionEventInfo = ev.getAction() + "";
                break;
        }
        Log.d(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : motionEventInfo = " + motionEventInfo);

        //事件一开始就由Activity所附属的Window进行分发,
        //如果返回true,整个事件循环就结束了,不在走onTouchEvent流程,
        //如果返回false意味着事件没人处理,所有事件往下分发给onTouchEvent来处理,
        //如果最后所有View的onTouchEvent都返回了false,那么Activity就要来做最后的收场。
        boolean isSuperDispatchTouchEvent = getWindow().superDispatchTouchEvent(ev);
        Log.e(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : Window.SuperDispatchTouchEvent = " + isSuperDispatchTouchEvent);
        boolean isNext = super.dispatchTouchEvent(ev);
        Log.d(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : isNext = " + isNext);
        return true;
    }


基类Activity的dispatchTouchEvent的源码:
   /**
     * Called to process touch screen events.  You can override this to
     * intercept all touch screen events before they are dispatched to the
     * window.  Be sure to call this implementation for touch screen events
     * that should be handled normally.
     *
     * @param ev The touch screen event.
     *
     * @return boolean Return true if this event was consumed.
     */
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
           // 空方法
            onUserInteraction();
        }
        
        //事件一开始就由Activity所附属的Window进行分发,
        //如果返回true,整个事件循环就结束了,不在走onTouchEvent流程,
        //如果返回false意味着事件没人处理,所有事件往下分发给onTouchEvent来处理,
        //如果最后所有View的onTouchEvent都返回了false,那么Activity就要来做最后的收场。
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        //分发给onTouchEvent处理,
        return onTouchEvent(ev);
    }


boolean isSuperDispatchTouchEvent = getWindow().superDispatchTouchEvent(ev)是boolean isNext = super.dispatchTouchEvent(ev)中的内容:
1、事件一开始就由Activity所附属的Window进行分发
2、如果isSuperDispatchTouchEvent 值为true,那么就super.dispatchTouchEvent(ev)就直接return true不在往下执行onTouchEvent事件,意味着事件的结束
3、如果isSuperDispatchTouchEvent 值为false,那么事件就会往下被分发到onTouchEvent中处理
4、Activity的onTouchEvent是最后来消化其他子View没有处理的touch事件

onTouchEvent

实现类的onTouchEvent方法,用来做Log信息跟踪:
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        String motionEventInfo = "";
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                motionEventInfo = "ACTION_DOWN";
                break;
            case MotionEvent.ACTION_MOVE:
                motionEventInfo = "ACTION_MOVE";
                break;
            case MotionEvent.ACTION_UP:
                motionEventInfo = "ACTION_UP";
                break;
            default:
                motionEventInfo = event.getAction() + "";
                break;
        }
        Log.d(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : onTouchEvent = " + motionEventInfo);
        //目前还不清楚mWindow.shouldCloseOnTouch(this, event)的具体源码
        boolean isNext = super.onTouchEvent(event);
        Log.d(GlobalUtils.TAG, "[MainActivity] onTouchEvent : isNext = " + isNext);
        return isNext;
    }
基类Activity的onTouchEvent的源码:
    /**
     * Called when a touch screen event was not handled by any of the views
     * under it.  This is most useful to process touch events that happen
     * outside of your window bounds, where there is no view to receive it.
     *
     * @param event The touch screen event being processed.
     *
     * @return Return true if you have consumed the event, false if you haven't.
     * The default implementation always returns false.
     */
    public boolean onTouchEvent(MotionEvent event) {
        if (mWindow.shouldCloseOnTouch(this, event)) {
            finish();
            return true;
        }

        return false;
    }

Activity的onTouchEvent算是Android 应用层上最后用来消化点击事件的最后防线了,然而对于super.onTouchEvent(event)中的mWindow.shouldCloseOnTouch(this, event)事件,目前还不清楚具体的作用,因为目前跟踪不到其内部源码。
总结:

Log信息如下:

04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : motionEventInfo = ACTION_DOWN
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle E/dfsu: [MainActivity] dispatchTouchEvent : Window.SuperDispatchTouchEvent = false
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : onTouchEvent = ACTION_DOWN
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] onTouchEvent : isNext = false
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : isNext = false
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : motionEventInfo = ACTION_UP
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle E/dfsu: [MainActivity] dispatchTouchEvent : Window.SuperDispatchTouchEvent = false
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : onTouchEvent = ACTION_UP
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] onTouchEvent : isNext = false
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : isNext = false




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值