View的事件处理机制

2017-10-12  本文已影响135人  LPhoenix

事件处理机制

先来看下dispatchTouchEvent(),该方法的默认会返回值由onTouch()和onTouchEvent()方法确定。

//由activity的dispatchTouchEvent
    public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();
    }
    if (getWindow().superDispatchTouchEvent(ev)) {
  //view处理了事件,事件就不会再传给自己的onTouchEvent();
        return true;
    }
    return onTouchEvent(ev);
}     

事件机制非常像上级给下级安排工作,上级获得到一个事件,第一时间是向下级问有没有人要处理该事件,下级的dispatchTouchEvent()方法返回值就是对上级的响应,默认情况下当然处理事件还是要靠动手的,onTouch/onTouchEvent就是手,当下级表示要处理的事件的时候,其也可以根据自身情况,决定是否动手处理该事件,onTouch/onTouchEvent返回true则表示下级动手处理了事件,返回false则表示下级并没有处理该事件,放任其自由,并不是所有的事件都有处理的必要。如果是true则表示我要处理,如果是false则表示我不处理。
当然默认下级的响应是要看自己的手能否处理得了事件,即看onTouch/onTouchEvent的返回值来决定对上级的响应,即决定着dispatchTouchEvent()的返回值。如果下级决定不处理事件,自己的dispatchTouchEvent()返回值为false,事件就会回交上级。

这是view的dispatchTouchEvent的核心源码,先判断mOnTouchListener,及onTouch的返回值,
然后在根据会返回值判断是否到达onTouchEvent,再获取onTouchEvent返回值
 if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }

        if (!result && onTouchEvent(event)) {
            result = true;
        }

这是activity的dispatchTouchEvent的源码,通过window将事件交给view,getWindow().superDispatchTouchEvent(ev),
再根据superDispatchTouchEvent(ev)返回值确定事件能否到自身的onTouchEvent();再获取onTouchEvent返回值

public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();
    }
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    return onTouchEvent(ev);
}

下面是自己结合API25源码及洋神的分析,来分析下onTouchEvent的源码

private static final int PFLAG_PRESSED = 0x00004000;//长按标示

private static final int PFLAG_PREPRESSED = 0x02000000;//短按标示

private static final int DEFAULT_LONG_PRESS_TIMEOUT = 500;//长按时间检测

private static final int TAP_TIMEOUT = 100;//短按时间检测

Down时:

Move时:

UP时:

setClickable(false)与setEnable(false)异同

有个大家应该都知道的问题就是setClickable(false)的问题,该方法在setOnClickListener()/setOnLongClickListener之前调用是没有效果的,由源码可得知,所以要在之后调用,另外setClickable(false)和setEnable(false)笼统的都是禁止点击的意思。但是setEnable(false)将控件能完全禁用,颜色会变灰色。

public void setOnClickListener(@Nullable OnClickListener l) {
    if (!isClickable()) {
        setClickable(true);
    }
    getListenerInfo().mOnClickListener = l;
}   

关于viewGroup事件处理机制,见下一篇文章ViewGroup事件分发机制源码分析

上一篇 下一篇

猜你喜欢

热点阅读