android事件传递机制的浅谈

想必大家有时会遇到需要自定义控件吧,这个时候就会遇到事件的传递和处理了,非常繁琐啊!百度上面一大票关于事件的传递机制,但是都千篇一律,都是dispatchTouchEvent

返回true,则事件被拦截,false则分发给子控件之类的,经过几天的研究发现这个事件传递并没有说的这么简单也没有想象中的难。

一般的点击事件、滑动事件都是用ACTION_DOWN、ACTION_MOVE、ACTION_UP组成的,android应用里面默认情况下,触摸事件是从activity开始传递,假设里面的view都不需要拦截事件,那么这个触摸事件会沿着里面的视图走一圈再回到activity,如果我们对某一个view绑定了一个事件监听器,那么这个事件只能被一个view消费。

注意:默认系统事件机制,一但ACTION_DOWN没有被一个ViewGroup或者View消费(即dispatchTouchEvent 返回为false),那么以后的ACTION_MOVE、ACTION_UP事件就再也不会分发到这个ViewGroup或者View上了(即该ViewGroup或者View再也不会调用dispatchTouchEvent 这个方法了


其实以上说的大家一般都清楚,但是当需要重写某个控件的时候又会犯难了,因为光知道以上的还不够,这个时候我们需要去看源码研究下,通过俺的鼓捣,发现了事件传递的规律:

假设activity中有一个ViewGroup,ViewGroup又有一个子View,下面写下事件传递顺序:

1、当事件没有被任何view消费的

dispatchTouchEvent(Activity) 事件传递给Window→ dispatchTouchEvent (ViewGroup)

onInterceptTouchEvent(ViewGourp)→ dispatchTouchEvent (View)→onTouchEvent(View)

→ onTouchEvent(ViewGroup)→ onTouchEvent(Activity)

2、当事件被ViewGroup消费,不传递给子View,onInterceptTouchEvent(ViewGourp)返回true

dispatchTouchEvent(Activity) 事件传递给Window→ dispatchTouchEvent (ViewGroup)→

onInterceptTouchEvent(ViewGourp) → onTouchEvent(ViewGroup)

3、当事件被子View消费, onInterceptTouchEvent(ViewGourp)返回false

dispatchTouchEvent(Activity) 事件传递给Window→ dispatchTouchEvent (ViewGroup)→

onInterceptTouchEvent(ViewGourp) → dispatchTouchEvent (View)→onTouchEvent(View)


其实一个触摸事件不管是activity还是viewgroup、view,都是从dispatchTouchEvent这个回调函数开始,里面会把触摸事件传给它的下一层,如果他的下一层dispatchTouchEvent返回了ture,则这个事件就回不去了,因为被下一层拦截到了,onTouchEvent方法只是在dispatchTouchEvent中最后调用的,因为会先把事件传递给下一层,如果下一层不要了才会执行到调用onTouchEvent这一步,而onInterceptTouchEvent只有viewgroup中才有,是对事件的再一次拦截。

这个是系统默认方式,但是如果重写上面的dispatchTouchEvent方法,就可以颠覆这个默认的规律,比如viewgroup传递给它的子view,我在他们的相关事件拦截方法里面都返回false,然后对他们都各自处理自己的事件,那么这样就不是一个事件只能被一个视图消费了。


接下来介绍一个超级好用的方法:

public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);

当子控件不想让父布局甚至祖先布局拦截事件,就调用此方法,生效期间是整个touch,一旦手指离开或者状态被清楚就失效。

具体使用场景,当父布局和子控件都有同方向的滑动事件,手指在子控件上的时候不让父布局消费滑动事件,代码如下:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(ev);
    }

最后用一张不知道哪位大神的图表总结下


暂时就水到这,这只是自己的一点心得,欢迎大家互相学习交流

转载请注明本文出自Alex老夫子的博客(http://blog.csdn.net/msn465780),谢谢支持!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值