点击事件传递规律

点击事件的分发过程有三个主要的方法:

onTouchEvent:

onTouchEvent是在view中定义的一个方法。处理传递到view 的手势事件。手势事件类型包括ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL四种事件。一旦onTouchEvent方法被调用,并返回true则这个手势事件就结束了,并不会继续传递到子控件。

onInterceptTouchEvent:

onInterceptTouchEvent是在ViewGroup里面定义的。Android中的ViewGroup布局类都会继承此类的。onInterceptTouchEvent是用于拦截手势事件的,每个手势事件都会先调用onInterceptTouchEvent。

onInterceptTouchEvent()用于处理事件并改变事件的传递方向。返回值为false时事件会传递给子控件的onInterceptTouchEvent();返回值为true时事件会传递给当前控件的onTouchEvent(),而不在传递给子控件。由于onInterceptTouchEvent()的机制比较复杂,有一下几种:

1.down事件首先会传递到onInterceptTouchEvent()方法
2.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move,up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。
3.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move,up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。
4.如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。
5.如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

dispatchTouchEvent

该方法用来进行事件的分发,即无论ViewGroup或者View的事件,都是从这个方法开始的。然后就会执行上面的操作,直到这个事件被消耗。通过源代码的分析,大体是这样的:如果一个事件传递到了ViewGroup处,首先会判断当前ViewGroup是否要拦截事件,即调用onInterceptTouchEvent()方法;如果返回true,则表示ViewGroup拦截事件,那么ViewGroup就会调用自身的onTouchEvent来处理事件;如果返回false,表示ViewGroup不拦截事件,此时事件会分发到它的子View处,即调用子View的dispatchTouchEvent方法,如此反复直到事件被消耗掉。


传递机制一些结论

【Android开发艺术探索内容整理】
(1)OnTouchListener的优先级比onTouchEvent要高
如果给一个view设置了OnTouchListener,那么OnTouchListener中的onTouch方法会被回调。这时事件如何处理还要看onTouch的返回值,如果返回false,那么OnTouchListener中的onTouch方法不会被回调,就轮到当前view的onTouchEvent方法会被调用;如果返回true,那么onTouchEvent方法将不会被调用。
在onTouchEvent方法中,如果当前view设置了OnClickListener,那么它的onClick方法会被调用,由此可见我们平时常用的OnClickListener的优先级最低,处于事件传递的尾端。
(2)当一个点击事件发生之后,传递过程遵循如下顺序:Activity -> Window -> View。
如果一个view的onTouchEvent方法返回false,那么它的父容器的onTouchEvent方法将会被调用,依此类推,如果所有的元素都不处理这个事件,那么这个事件将会最终传递给Activity处理(调用Activity的onTouchEvent方法)。
(3)同一个事件序列是指触摸屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中所产生的一系列事件,这个事件徐柳以down事件开始,中间含有数量不定的move事件,最终以up事件结束。
(4)正常情况下,一个事件序列只能被一个View兰家且消耗,原因参考5),因为一旦一个元素拦截了某些事件,那么同一个事件序列的所有事件都会交给它处理,但不是绝对的,可以强制。
(5)某个View一旦决定拦截,那么这个一个事件序列都只能由它来处理,并且它的onInterceptTouchEvent方法不会被再次调用。
(6)某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false),那么这个一个事件序列都不会交给它来处理,并且事件将重新交给它的父容器去处理。
(7)如果它消耗ACTION_DOWN事件,但是不消耗其他类型事件,那么这个点击事件会消失,父容器的onTouchEvent方法不会被调用,当前view依然可以收到后续的事件,但是这些事件最后都会传递给Activity处理。
(8)如果所有的View都不处理事件,这个事件最终会消失。
(9)ViewGroup默认不拦截任何事件,因为它的onInterceptTouchEvent方法默认返回false。
(10)View没有onInterceptTouchEvent方法,也就是不拦截事件,只要有时间传递给它,它的onTouchEvent方法就会被调用。
(11)View的onTouchEvent默认都会消耗事件,也就是onTouchEvent方法返回true。除非它是不可点击的(clickable和longclickable同时为false)。View的longclickable默认为false,clickable要看情况,比如Button默认是true,也就是Button默认会消耗事件,onTouchEvent方法返回true。
(12)View的enable属性不影响onTouchEvent的默认返回值。哪怕一个view是disable状态,只要它的clickable或者longClickable有一个是true,那么它的onTouchEvent就会返回true。
(13)onClick会发生的前提是当前View是可点击的,并且它收到了down和up事件。
(14)事件传递过程是由外向内的,即事件总是先传递给父元素,然后再由父元素传递给子View,但是子元素可以通过requestDisallowTouchEvent方法干扰父元素的分发过程,但是down事件除外。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值