Android开发艺术探索笔记(11)- View的事件分发

View事件的分发使得我给定义的事件能正确响应,核心原理竟然只有短短几行伪代码,Are you kidding me??不信??直接上码

public boolean dispatchTouchEvent(MotionEvent event) {
    boolean consume = false; 
    if (onInterceptTouchEvent(event)) {
        consume = onTouchEvent(event);
    } else {
        consume = child.dispatchTouchEvent(event);
    }
    returen consume;
}

重点在这3个方法

dispatchTouchEvent

用于View事件的分发。只要事件能传给当前View,这个方法一定会被调用。也就是说,只要父View不拦截这个事件,这个事件会传到当前View,这个方法一定被调用。

onInterceptTouchEvent
判断当前View是否拦截事件,如果拦截了,此方法只会被调用一次。我看了作者给出的源码才知道。毕竟上面只是伪代码。

onTouchEvent
如果当前View拦截了事件,则在这里处理事件,并返回是否消耗事件。是否消耗直接影响父View的dispatchTouchEvent的返回值。

既然原理都差不多明白了,具体看看Android的View的事件分发。

我们在Activity触碰屏幕发生事件时,Activity会转给Window处理事件,Window是默认不拦截事件的,然后由Window的子View去处理,也就是decor View。这个decor View的底层(id为android.R.id.content的Layout),就是我们在Activity.setContentView中的View(Layout2)的父容器。也就是decor View有一个子View(Layout1)叫android.R.id.content,Layout1是Layout2的父容器,所以我们想要得我们设置的View(Layout2),就得用

((ViewGroup)getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0);

然后事件就会转到我们Layout2里面,再根据View的事件分发,再交给子View处理。如果Layout2及子View都拦截处理事件的话,最终会调用Activity的onTouch方法,交回Activity处理。(貌似是这样)

作者给出了ViewGroup分发事件的部分源码,我觉得挺重要的,这里帖图出来,以便以后自己分析。

ViewGroup事件分发代码

作者说明了一点,如果View拦截了ACTION_DOWN事件,那么在ACTION_UP发生之前的一系列事件都该由当前View处理。仔细想想,这样做事有道理的。事件都是由点击屏幕开始,然后到一系列的移动,或者没有移动,最后离开屏幕结束,这才是完整的一个事件。所以有一个条件是判断当前事件是ACTION_DOWN,事件的开始。还有一个判断mFirstTouchTarget是否为null,这个是什么意思?其实这个mFirstTouchTarget值得是成功处理事件的Views,是一个链状,因为它有next节点。如果View自己拦截了事件,那么mFirstTouchTarget=null,下次就不会调用判断是否onInterceptTouchEvent判断是否拦截,直接执行onTouchEvent事件。所以onInterceptTouchEvent只会之执行一次。如果不为mFirstTouchTarget!=null,证明自己没有处理,只能等下一次ACTION_DOWN的到来了。

啊!子View还可以拦截ViewGroup的除了ACTION_DOWN之外的事件,就是FLAG_DISALLOW_INTERCEPT标志位。子View可以调用requestDisallowInterceptTouchEvent方法设置FLAG_DISALLOW_INTERCEPT标志位,使得ViewGroup无法拦截除了ACTION_DOWN之外的事件。由于ACTION_DOWN时,ViewGroup会重置FLAG_DISALLOW_INTERCEPT这个标志位,所以对这个事件无效。

还有一个问题值得记录一下。View默认有onTouchEvent方法,使用时还调用该View的setOnTouchListener的onTouch方法,同样是处理事件,先后顺序是怎么样呢?

有代码分析,是先会调用我们设置setOnTouchListener的onTouch方法,然后根据setOnTouchListener的onTouch方法的返回值,看要不要调用该View的onTouchEvent方法。如果返回ture,则证明要在setOnTouchListener的onTouch方法消耗了事件,该View的onTouchEvent方法不会被调用。否则,该View的onTouchEvent方法还是被调用。如果我们调用该View的setOnClickListener方法,监听了click事件,View的onTouchEvent方法里面,会调用setOnClickListener的onClick方法,所以View得click事件很容易拦截,因为click事件的优先级最低。

上面是ViewGroup(也是一种View)的事件分发过程。子View(不是ViewGroup)只是处理事件,返回是否处理事件,对ViewGroup有影响。ViewGroup会遍历所有子View可以处理事件,依据大概是是否播放动画,事件的坐标是否落在该子View的范围内,如果成立就分发事件给该子View处理。如果该子View成功处理事件,mFirstTouchTarget就会被赋值,这直接影响ViewGroup。

具体代码请查阅书。这里我关心的是View事件的分发,其他不是很care。View的事件分发就到这了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值