android 向下传递触摸,Android触摸事件传递(下)

上一篇中,我说明了Android中Activity和View触摸事件的传递流程,现在我们来继续学习MotionEvent在View的容器ViewGroup中的传递过程。

首先,ViewGroup继承于View,我们在开发中经常使用的LinearLayout,RelativeLayout,FrameLayout等都继承于ViewGroup,而Button,TextView,ImageView等都继承于View,ViewGroup对View最基本的扩展的功能就是可以添加子View。

ViewGroup触摸事件的传递,我们要先了解onInterceptTouchEvent()方法,这个方法默认返回false,表示ViewGroup是否拦截触摸事件,即如果返回true,拦截触摸事件,则不会将任何触摸事件ev向下传递给它的子View,换一句话说,这个时候,ViewGroup就变成了我们上一篇说的View,完全走View的触摸事件传递流程,同样的我们来写代码验证。

我们自定义一个EventRelativeLayout 继承于RelativeLayout,重写onInterceptTouchEvent方法,返回true, 重写onTouchEvent方法,返回false,然后将我们Activity的根布局改成EventRelativeLayout,然后在onCreate中给它添加onTouchListener,

a4bb029c0b7c

a4bb029c0b7c

a4bb029c0b7c

运行App,点击按钮,查看打印日志,

a4bb029c0b7c

可以看到,我们的button没有接收到触摸事件,现在将onInterceptTouchEvent返回值改为false,再次运行App,点击按钮,查看打印日志,

a4bb029c0b7c

很明显,我们的按钮的触摸事件和它的父容器的触摸事件,都触发了,这是因为,我们EventBtn的onTouchListener方法和onTouchEvent方法都返回false,没有消费触摸事件,事件会向上继续传递。那么如果ViewGroup不拦截触摸事件,事件在它的子Views中又是如何传递的呢?

触摸事件ev会按照子View加入ViewGroup先后顺序相反的顺序,依次有机会去消费此触摸事件ev,即最后加入的最先有机会消费此触摸事件,当然,它消费的前提是,触摸点的坐标在这个子View的frame范围之内,其实只需要判断触摸事件的Point是否在子控件的Rect范围之内。我们同样写代码验证。

重写EventBtn类,如下,

a4bb029c0b7c

修改onCreate中的代码

a4bb029c0b7c

修改main布局文件

a4bb029c0b7c

修改布局文件,让三个按钮完全重合,加入的顺序,分别是btn1,btn2,btn3,如果按照我们的结论,触摸事件的传递顺序应该是btn3->btn2->btn1->ViewGroup->Activity,我们运行App,点击按钮,查看打印日志,

a4bb029c0b7c

我们可以看到,日志 打印的顺序呢,跟我们的结论一致,也就验证了我们的结论。但是我们仔细想来,好像还有点问题,就是我们一个按钮点击的动作,至少应该包含了ACTION_DOWN,ACTION_UP,二个触摸事件,但是我们打印的日志,显然只是一个触摸事件,那这是为什么呢?

为了搞清楚上面的问题,我们继续来到View的dispatchTouchEvent方法中,我们看到下面的一段代码

a4bb029c0b7c

我们也很好读懂,如果事件是ACTION_UP或者ACTION_CANCEL,表示触摸结束,但是还有第三种是 如果触摸事件是ACTION_DOWN 并且result==false,同样停止嵌套的触摸事件传递,即后面的ACTION_MOVE,ACTION_UP都不会触发,因为在我们上面的例子中,没有消费触摸事件,返回的都是false,所以只触发了ACTION_DOWN事件。同样,我们可以利用代码来验证我们上面的结论,我们打开EventBtn类中dispatchTouchEvent方法中的日志打印代码,同时我们将btn3的onTouchListener方法返回true,消费掉触摸事件,然后运行App,点击按钮,查看日志。

a4bb029c0b7c

a4bb029c0b7c

a4bb029c0b7c

我们看到,这里一次按钮点击触发了4个事件,分别是ACTION_DOWN,ACTION_MOVE,ACTION_MOVE,ACTION_UP,同时所有事件全部被btn3消费掉了,这就验证了我们上面的结论,因为此时我们让btn3消费了ACTION_DOWN事件,所以后续触摸事件得以继续触发。通过上面的知识,如果我们不希望响应触摸事件,可以给ACTION_DOWN触摸事件,返回false,或者如果我们希望提前结束一个触摸事件周期,可以给targetView 发送 ACTION_CANCEL事件,如下:

a4bb029c0b7c

关于Android中ViewGroup的触摸事件传递就介绍到这里,难免很多地方有错误纰漏,但是我能够坚持把这些写出来,我觉得我已经有一点小小的提高了,很开心~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值