您的位置:首页 > 移动开发 > Android开发

android事件分发的梗?

2016-02-17 14:07 435 查看
android事件分发有许多坑,今天带大家领略个深坑。有时候尝试了很多方法之后才发现其实不是安卓系统本身的不灵活,谷歌工程师感觉实在比我们牛逼很多,所以不要在怀疑安卓系统有什么自身的缺陷。好了,废话少说,开始问题。问题是,scrollview里面嵌套gridview,listview,事件冲突在什么地方呢?就是gridview作为一个整体可以滑动,同时gridview里面的item项如果长按位置可以改变,具体效果可以看支付宝的首页。这个问题我当时的解决思路是:

1、只能从业务上去分开,如果是快速滑动应该是整体滑动,如果长按item项的话,应该就是item移动。我们知道,倒是是快速滑动还是长按,只有通过在一定事件move事件的位置距离down事件位置距离来判别,那么问题来了,当我们事件走到move的时候才知道move事件应该有谁消费。这个梗非常奇特在哪儿呢?因为安卓是事件分发规则是这样的,如果一个down事件是被viewgroup消费掉,那么其余的move和up事件会直接跑到viewgroup,跟子view也就是本文中的gridveiw就是无关的了。这儿是正常的事件分发和消费逻辑。那么对于这个问题就是个矛盾,因为我必须等到move事件才能知道down事件应该被谁消费,(是scrollview还是gridview)消费。这个不符合常理。

2、由于上述矛盾,我一直想不通,为啥down事件被scrollview消费掉了,move和up都不走这个gridview了,直接百度了很多理论,说事件消费从子view向父view传递,这个是不对的,大家可以试验。如果初始状态下,让down事件给scrollview消费,那么gridview将接受不了move事件和up事件,那么gridview的item拖动依赖的move和up事件就没法捕获,这样就不行的。我甚至想到了,首先down事件给scrollview消费掉,然后move和up都直接让scrollview接受了,通过move事件判断是长按以后,再把move事件和up事件传递给gridview,这样也有两条思路,一种是代码模拟点击,一种是通过发送消息。代码模拟点击无法起到作用,因为在move事件后,up事件之前,performclick是起不到作用的。通过handler发送消息,由于代码量太大,我自定义的gridview等于要重新写,还不知道有啥问题所以作罢。

注意:gridview里面item拖动都是自己定义写的,本身gridview的item项不具备拖动和拖动后位置保存的功能。

3、由于这个矛盾,后来又想了一条方法,比如在事件进入scrollview的dispatchtouchevent方法之前能不能就判断好,到底down是由scrollview消费还是gridview消费。这样思路看起来确实非常清晰,但是问题又来了,事件分发系统,down和move,up都是硬件产生,经过安卓系统分发的,不通过重写那几个方法,你自己根本无法去处理这些信息的。只好作罢。

4、一直在思考,为啥事件分发这么坑,是不是非常坑,难道只能在scrollview里面通过重写onInterceptTounchEvent来拦截或不拦截事件传递么,难道不能在gridview里面动态的决定是否move和up事件是否被scrollview拦截么?按照正常的事件分发机制确实不能,最终谷歌工程师提供了一个牛逼的方法那就是 requestDisallowInterceptTouchEvent(true),首先膜拜下这个方法先,我相信这个方法将是解决事件冲突最有力的方法。参数为true代表不scrollview不拦截事件,false代表拦截。这个方法好处就在于,如果down事件被scrollview消费掉了,move事件,up事件也可以传递到gridview里面啦。正好解决了这个矛盾。我通过判断长按,通过这句话传入参数true,让scrollview不拦截move事件,这样gridview就可以正常拖曳item了。如果我不写这句话,在gridview范围了整体滑动的时候,滑着滑着scrollview就会拦截move事件,(至于为啥我不知道,因为onInterceptTouchEvent我的返回值是super.onInterceptTouchEvent,这样就直接交给了父类去处理,这个地方如果单纯返回ture或者false应该都不行,这个地方也要特别注意。)进而产生了action_cancel事件传递给gridview,这个事件产生以后gridview消化掉这个事件后,gridview就不能接受move和up事件了,这两个事件就传递到了scrollview,这样整体滑动就能够产生了。这个里面也有个关键点就是为啥滑动着滑动着,刚开始几个move事件都是有gridview消耗的,可能是gridview不能消耗这种事件,进而系统反馈产生了cancel事件,终止gridiview对move事件的消耗,这样move事件就能够直接发送个scrollview了。这个里面的情节还比较复杂,还要看源码,暂时没这个精力了,这个问题解决了就好了,谁知道这个点的原因可以评论告诉我下,谢谢了。这个也反映了事件分发机制其实还是非常复杂的,很多复杂的情况都是由系统去处理的,单纯重写几个方法想处理复杂的事件冲突估计有点困难了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: