事件的传递(一篇老外的博客)


本人在搜索事件分发的文章时,偶然看到的一片博文,条例很清晰,很有启发性,决定整理下来。

事件的传递

某时某刻,你不得不亲自操刀去处理点击事件,此时你不能仅仅依靠那些正确的某某监听器来达到效果.我特别不喜欢那些

类似于明信片般简洁的答案,例如触摸事件是怎样在View体系中传递的,完全没有鸟用。

你需要更多信息,但是作为了解事件分发的起点,如果直接去了解那些底层细节也是不明智的。

下面是我的方法,也许有些冗长,但绝对能让你一步步的明白。

一些假设

我们仅仅只关注那些最重要的事件(其实是动作):DOWN,MOVE,UP和CANCEL.

一个手势起始于一个DOWN事件,后面也许会有许多MOVE事件,一个UP事件,一个CANCEL事件

当用户从屏幕上释放时,系统就知道这个手势结束了。当我谈论“手势的剩余部分时”,我的意思是指该手势

其他的后续的动作MOVE,UP,CANCEL。我会忽略多点触摸,即认为仅仅是一根手指,同样,我会假设所有的View都没有onTouchListener监听器

 

如上图,整个View体系非常明朗。

我们的手指在红色处按下,然后不停的滑动

默认情况

我们假设所有View的相关方法都是默认的

1.DOWN事件传到C的onTouchEvent方法,改方法返回false,表示“我并不关心这个手势”

2.因为C的onTouchEvent返回了false,DOWN事件被传到了B的onTouchEvent方法,该方法不关心该手势

 同样返回false

3.后面同上。由于B的不关心,DOWN事件被传到A的onTouchEvent方法,同样返回false

由于所有的View都不关心这个事件,所以该手势后面的动作都不会传给他们了(如MOVE,UP,CANCEL)

处理事件

现在我们假设C实际上是关心该事件的,可能他被设为只可点击的,或者你自己实现了onTouchEvent

1.DOWN事件被传到C的onTouchEvent方法,你可以做你想做的事情,然后他返回true.

2.因为C通过返回true告诉系统他会接管这个手势,实际上他消费了DOWN事件,那么DOWN事件

就不会传到B和A的onTouchEvent方法了

3.同样,由于C已经接管了这个手势,那么这个手势剩下的动作都会被传到C的onTouchEventy方法

后续做动作的返回值实际上已经不重要了,但是为了连续性,应该返回Ttrue

拦截事件

现在我们要面对onInterceptTouchEvent了,这个方法存在于ViewGroup中,并不存在View中

在一个View的onTouchEvent被调用之前,这个View的祖先们是可以拦截这个事件的,也就是说

他们可以偷走这个事件。现在我们重新回顾一下“处理事件”部分

1.DOWN事件被传递到A的onInterceptTouchEvent方法中,返回false,表示他不想拦截

2.DOWN事件被传递到B的onInterceptTouchEvent方法中,同样返回false

3.DOWN事件被传递C的onTouchEvent方法中,返回true,因为C想处理该事件

4.现在改手势的下一个事件来了,即MOVE事件。MOVE事件被传到A的onInterceptTouchEvent方法中

返回false,B也会做同样的处理

5.MOVE事件传递到C的onTouchEvent方法中,就像“处理事件”部分一样

6.假设A和B的onInterceptTouchEvent方法继续返回false,该手势剩下的动作会以同样的流程进行

我们注意到即使ViewGroup的onInterceptTouchEvent方法之前已经返回了false,后续的事件(如MOVE)

仍然调用了该方法,这与onTouchEvent方法是不同的

注:如果C的onTouchEvent在这里返回了false,接下来的事就像“默认情况”部分一样,虽然B和A已经

用行动表明他们不关心该手势,但是事件还是会传给他们的onTouchEvent方法

拦截事件(续)

现在我们更近一步,我们上面说到B并不拦截DOWN事件,现在我们假设他会拦截接下来的

MOVE事件。他之所以这么做也许因为B是一个ScrollView,如果用户是轻轻敲打了一下它里面的

View,被敲打的View自然会去响应点击事件。但是,一旦用户尝试滑动,此时不再是点击了--这表示用户想要滑动

那么B就会接管这个手势了。

1.DOWN事件被传递到A的onInterceptTouchEvent,返回false

2.DOWN事件被传递到B的onInterceptTouchEvent,返回false

3.C的onTouchEvent返回true

4.MOVE事件被传递到A的onInterceptTouchEvent,返回false

5.MOVE事件被传递到B的onInterceptTouchEvent,此时用户的手指已经在屏幕上滑动了一段距离

B的onInterceptTouchEvent返回true

6.刚才的MOVE事件会被转化成一个CANCEL事件,这个CANCEL事件会被传递到C的onTouchEvent

7.接下来是下一个MOVE事件,A的onInterceptTouchEvent返回false

8.此时这个MOVE事件不会传递到B的onInterceptTouchEvent,一旦你这个方法中返回了true,他就不会再被调用了。MOVE事件会被传递到B的onTouchEvent,剩下的事情也会传递到这里

9.C不会收到该手势后续的事件(此次C一共收到DOWN和CANCEL两个事件)

下面的事情值得注意:

*如果一个ViewGroup拦截最初的DOWN事件,那么这个事件也会被传递到该ViewGroup的onTouchEvent

*另一方面,如果ViewGroup只是拦截了后面的事件(如MOVE),这个事件将会被转化成 一个CANCEL事件,然后这个CANCEL传递给之前处理过该手势的,他的孩子。这个ViewGroup会处理后面的事件(不包括这次--MOVE事件已经被转化成了CANCEL给了孩子)

谨记:

掌握了这些,你就可以走的更远

C拥有一个方法,requestDisallowInterceptTouchEvent,可以阻止B偷走他的事件

如果你确实想大干一场的话,你可以重写dispatchTouchEvent事件,当事件来临的时候,随意处理他们

原文地址:http://balpha.de/2013/07/android-development-what-i-wish-i-had-known-earlier/(也许要翻墙哦)















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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值