Android View事件体系汇总其三

上篇文章 Android View事件体系汇总其二 主要介绍了View的滑动与弹性滑动。接下来我们就来介绍View事件体系的核心知识与难点-View的事件分发机制。

介绍事件分发机制之前我们先来介绍三个重要的方法,点击事件的分发过程主要由着三个方式共同完成:

boolean dispatchTouchEvent(MotionEvent ev)

用于进行事件的分发,如果事件能够传递给View,那么此方法就一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvnet方法的影响,表示是否消耗当前事件。

boolean onInterceptTouchEvent(MotionEvent ev)

在上述方法的内部调用,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一事件序列中,此方法不会被再次调用,返回结果表示是否拦截当前事件。

boolean onTouchEvent(MotionEvent ev)

在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一事件序列中,当前View无法再次接收到事件。

 

下面我们就分析一下点击事件分发的详细过程,这里分为两种情况,接收首先点击事件的位置是View还是ViewGroup:

当首先接收事件的是ViewGroup

点击事件产生后,首先会传递给它,这时ViewGroup的dispatchTouchEvent方法就会被调用,紧接着在方法内就会调用它的onInterceptTouchEvent方法,询问当前ViewGroup是否拦截此事件。

如果ViewGroup的onInterceptTouchEvent方法返回为true,就表示它要拦截当前事件,接着事件就会调用它的onTouchEvent方法。如果ViewGroup的onInterceptTouchEvent方法返回false,那么表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvnet方法就会被调用,继续上述过程直至事件被最终处理。

当首先接收事件的是View

当一个View接收到事件时,如果它设置了OnTouchListener,那么OnTouchListener中的onTouch方法就会被调用。这是事件如何处理还要看onTouch的返回值,如果返回false,那么当前View的onTouchEvent方法就会被调用。如果返回true,那么onTouchEvent方法就不会被调用。

由此可见,View设置的onTouchListener,其优先级比onTouchEvent要高。在onTouchEvent方法中,如果有设置onClickListener,那么它的onClick方法会被调用。可以看出,平时我们最常用的OnClickListener,其优先级最低,处于事件传递的末端。

 

·当一个事件产生之后,他的传递过程遵循一项顺序:Activity->Window->View,即事件总是首先传递给Activity,Activity在传递给Window,最后Window再传递给顶层的View,顶层View接收到事件后,就会按照事件分发机制去分发事件。这里考虑一种情况,如果一个View的onTouchEvent返回false,即这个View不消耗此事件,那么这个事件就会向父级传递,那么它的父容器的onTouchEvnet将会被调用,依此类推,当所有的父容器都不消耗此事件,那么这个事件最终会被传递给Activity处理,即Activity的onTouchEvent方法被调用。这个其实也很好理解,比如我向下分配了一个任务,如果这个组内员工感觉很棘手,无法完成(onTouchuEvnet 返回 fasle),但问题终归是要解决的,所以它将问题又反馈给了我,交由我来处理,如果我解决了这个问题,相当我消耗了这个事件(onTouchEvent 返回 true)。如果我也完成不了,那么就需要向更上一级的领导反馈,交由他们处理。这样来看View的事件传递机制还是很贴近显示的,便于我们理解。

 

结论总结:

1,同一个事件序列是指从手指触碰到屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中产生的一系列事件。

2,正常情况下,一个事件序列只能被一个View拦截并处理。因为一个元素拦截了某事件,那么同一个事件序列内所有的事件都会交给它处理,因此同一个事件序列中的事件不能分别交给两个View同时处理。(但事情总是没有绝对的!通过特殊手段,可以将一个View本应自己处理的事件通过onTouchEvent强行传递给其他View处理)。

3,某个View一旦决定拦截,那么这一个事件序列都只能交由它来处理(如果事件能够传递给他的话),并且它的onInterceptTouchEvent不会在再被调用。这个也很好理解,就是说当一个View决定拦截一个事件后,那个系统会把同一事件序列内的其他事件都直接交给他处理,因此就不用再调用View的onInterceptTouchEvent去询问它是否需要拦截了。

4,某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent 返回 false),那么同一事件的其他事件都不会再交给它处理了,并且事件重新交给他的父容器去处理,即父容器的onTouchEvent会被调用。这个也很好理解,如果领导交给一个员工去处理一件事,如果这个员工没有处理好,那么短期内领导就不敢将同一关联下的事情交给他处理了。

5,如果一个View不消耗ACTION_DWON以外的其他事件,那么这个这个点击事件就会消失,此时父容器的onTouchEvent并会被调用,并且当前View仍可以收到后续事件,只不过View不会消耗后续事件,最终这些消失的点击事件会传递给Ativity处理。

6,ViewGroup默认不拦截任何事件。源码中ViewGroup的onInterceptTouchEvent方法默认返回false。

7,View没有onInceterptTouchEvent方法,一旦有点击事件传递给他,那么它的onTouchEvent方法就会被调用。

8,View的onTouchEvent默认都会消耗事件(返回true),除非它的clickable和longClickable同时设置为false。View的longClickable默认为false;clickable要分情况,比如Button默认为true,TextView默认为false。

9,事件传递过程是由外向内传递的,即事件总是先传递给父容器。事件的消耗是由内向外传递的,即总是要先询问子元素是否消耗事件,如果子元素不消耗,才能向上传递给父容器。

10,在子元素中可以通过requestDisallowInterceptTouchEvent方法可以干预父元素的事件分发过程,但是ACTION_DWON事件除外。

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值