Android 触摸事件系列一:原始View与ViewGroup的事件处理

View 的dispatchTouchEvent 与 onTouchEvent

public boolean dispatchTouchEvent(MotionEvent event) {

    ......

    if (onFilterTouchEventForSecurity(event)) {
        //noinspection SimplifiableIfStatement
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }

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

    ......

    return result;
}
  • View 是没有 onInterceptTouchEvent的 。当事件传递给它时 。必定会触发它的 dispatchTouchEvent ,也必定触发它的 onTouchEvent 。
  • mOnTouchListener 的处理优先级高于 onTouchEvent
  • mOnTouchListener 返回 true , 则不会调用 onTouchEvent 。
  • View 的 dispatchTouchEvent 返回值 和 mOnTouchListener 以及onTouchEvent 有关。

View onTouchEvent 逻辑如下:

    public boolean onTouchEvent(MotionEvent event) {
        final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
                || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;

        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
			    ......
            return true;
        }
        return false;
  • View clickable == true时 ,任何事件默认都返回True 。 clickable == false 时,任何事件都返回false 。可以通过 xml 中设置clickable 属性,也可以通过代码设置 Listener 。有的控件默认是可点击的如:Button 。 TextView 默认clickable 为false。

ViewGroup 的dispatchTouchEvent

   public boolean dispatchTouchEvent(MotionEvent ev) {
		boolean consume = false;
		if(intercepted || mFirstTouchTarget == null){
				// ViewGroup  将自己的角色定位成View ,用View 的dispatchTouchEvent ,自己处理事件
				consume = super.dispatchTouchEvent(event);
		} else if(mFirstTouchTarget != null){
				consume = mFirstTouchTarget.dispatchTouchEvent(ev);
		}
		return consume ;
	}

关于拦截 :

            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }

注意到下面那个 intercepted = true; 也就是 ViewGroup 它 很想拦截 。具体情况有以下几种。

  • ACTION_DOWN ,也就是刚开始一个事件序列, 子View们 请求disallowIntercept 或者ViewGroup 没有重写 onInterceptTouchEvent 。 这时 子View 们是有 机会处理 Down 事件的。
  • ACTION_MOVE , 此时 mFirstTouchTarget == null 。也就是说没有子View 对
    Down 事件 返回 true。 那么ViewGroup 也甭判断了 。 直接拦截。
  • ACTION_MOVE , 此时 mFirstTouchTarget != null 。有子View 的dispatchTouchEvent(ACTION_DOWN) 返回 true 。 那么 又进入到了权利角斗的环节了,View 是否允许ViewGroup 拦截 ,允许则 ViewGroup 判断是否拦截。

拦截后会发生什么:

  • 单指触摸下,会将mFirstTouchTarget 置为空
  • ViewGroup 自己处理 MotionEvent ,也就是调用 自身的 onTouchEvent 。
  • 拦截ACTION_MOVE ,会发送 Cancel 事件给 上一个mFirstTouchTarget 。
  • 当ViewGroup 拦截事件后,子View 再也没有 处理事件的机会了。(很纯的责任链模式啊!!!)

正是由于 父ViewGroup 拦截后,子View 再没有机会处理后续的触摸事件,就导致了Android 处理事件的局限性,也为后面推出 NestScoll 机制埋下了伏笔。

View 对 ACTION_MOVE返回false

当一个View 或者 ViewGroup 能够接触到 Action_MOVE 的时候,就代表 它的dispathTouchEvent 对 ACTION_DOWN 返回了 true 。 此时 mFirstTouchTarget 已经不为 null 了,就算 对 ACTION_MOVE返回false ,也不会影响到 它接收后续的事件。 不过返回 false 的 ACTION_MOVE 事件会 交给 Activity 处理。

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean result = super.onTouchEvent(event);
        Log.e("touch_tag"," MainActivity  " + MotionEvent.actionToString(event.getAction()) + " result = " +result);
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值