Android 事件分发

三个对象

Activity , View 和 ViewGroup,虽然 ViewGroup 是 View 的子类,但这里的 View 特指非 ViewGroup 的 View ,如 TextView 。

三个方法

  • dispatchTouchEvent 事件分发,返回结果受当前 View 的 onTouchEvent 和 下级 View 的 dispatchTouchEvent 影响,表示是否消耗当前事件。如果返回 false 将停止分发并调用父元素的 onTouchEvent;返回 true 将直接停止分发;返回 super 的方法将向下分发。
  • onInterceptTouchEvent 事件拦截,只存在于 ViewGroup 中,返回结果表示是否拦截某事件。如果当前 View 拦截了某个事件(返回 true),拦截后将调用当前 View 的 onTouchEvent 方法;否则将继续向下分发。
  • onTouchEvent 事件处理,返回结果表示是否消耗当前事件。如果事件没有被消耗(返回 false),则将继续调用父元素的 onTouchEvent;如果被消耗则停止分发(返回 true)。

三者的关系用伪代码表示:

public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean consume=false;
        if (onInterceptTouchEvent(ev)){
            consume=onTouchEvent(ev);
        }else {
            consume=child.dispatchTouchEvent(ev);
        }
        return consume;
    }
默认值
  1. ViewGroup 默认不拦截任何事件
  2. 一个 View 中 clickable 和 longClickable 如果有一个为 true,则其 onTouchEvent 默认返回 true。
  3. View 的 enable 属性不影响 onTouchEvent 默认返回值
requestDisallowInterceptTouchEvent

requestDisallowInterceptTouchEvent 可以在子元素中干预父元素的分发过程,要求父元素跳过自身的 onInterceptTouchEvent 事件。只在本事件序列有效。

getParent().requestDisallowInterceptTouchEvent(true);
总结

Android 中事件的分发过程是由外到内(dispatchTouchEvent / onInterceptTouchEvent),再由内到外(onTouchEvent)。 dispatchTouchEvent 决定是否继续分发,onInterceptTouchEvent 决定是调用自己的 onTouchEvent 还是继续向下分发,onTouchEvent 决定是否调用父元素的 onTouchEvent 方法。

事件序列

事件序列是指从手指接触屏幕到离开屏幕这个过程中的一系列事件,由一个 down 事件和一个 up 事件以及中间的若干个 move 事件组成。上面说的事件分发都是针对 ACTION_DOWN 事件,其他事件分发还有一些其他规则。

  • 一次事件分发过程中只能有一个 onTouchEvent 返回 true,其他事件也只到此元素。

  • 一个 View 一旦决定拦截,那么整个事件序列都将交给他去处理,并且他的 onInterceptTouchEvent 不会再被调用。

  • 一个 View 一旦开始处理某个事件序列,如果不消耗 ACTION_DOWN (onTouchEvent 返回了 false),那么同一序列的其他事件将交给其父元素处理,即父元素的 onTouchEvent 会被调用。

  • 一个 View 消耗了 ACTION_DOWN 事件,但是不消耗其他事件,那么不会调其父元素的 onTouchEvent 事件,而是直接调用 Activity 的 onTouchEvent 事件

View 的事件监听

OnTouchListener

由下面源码可以看出,OnTouchListener 的调用也是在 dispatchTouchEvent 中,而且在 onTouchEvent 之前。并且如果 OnTouchListener 返回 true ,onTouchEvent 将不再调用。

public boolean dispatchTouchEvent(MotionEvent event) {  
    if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&  
            mOnTouchListener.onTouch(this, event)) {  
        return true;  
    }  
    return onTouchEvent(event);  
}  
点击事件

点击事件分为 click 和 longclick,他们是在 onTouchEvent 中触发的,也就是说如果 OnTouchListener 返回了 true ,则此 View 的点击事件都不会触发。

OnClick 当 view 捕捉到 ACTION_DOWN 和 ACTION_UP 事件并且没被消费时执行;

OnLongClick 当view捕捉到ACTION_DOWN并且持续时间到达阈值时执行,此方法有一个返回值。若返回false,表示事件未被消耗,还会继续传递,将被OnClick捕获;若返回true,则表示此事件被消费,不再进行传递,也就是不会触发OnClick。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值