View的事件体系——View的滑动冲突
滑动冲突,当界面内外两层都可以进行滑动时,就会出现滑动冲突,这是一个非常让人困扰的问题,但是当你足够理解View的分发机制时,这些问题就很好解决了。
1.常见的滑动冲突场景
- 场景1——外部滑动方向与内部滑动方向不一致
- 场景2——外部滑动方向和内部滑动方向一致
场景1,这种场景下导致的结果是内外两层只能有一层进行滑动,这是因为这两者之间的滑动具有冲突。但是,现主流App大多数都会采取ViewPager和Fragment进行左右横向的页面切换,然后再fragmen中放置ListView或者RecyclerView,当我们使用时会发现,并没有我们所提到的滑动冲突啊。那是因为ViewPager已经帮我们处理了滑动冲突!!! 如果我们不使用ViewPager而是自定义一个可以横向滑动的View,那么这时我们就需要手动处理滑动冲突。
在实际开发中这种场景主要指外层上下滑动、内层左右滑动或者外层左右滑动、内层上下滑动。
场景2,这种场景下导致的结果是要么只有一层能够滑动,要么两层都滑动的很卡顿。因为当你手指进行滑动的时候,系统无法知道你想让哪一层进行滑动。
在实际开发中这种场景主要指内外两层同时上下滑动或者内外两层同时左右滑动。
当然还有上面两种组合起来,三层甚至多层嵌套产生的冲突,但是不管是多么层,其解决的思路都是一模一样。所以遇到多层嵌套也不用惊慌,一层一层处理即可。
2.滑动冲突的处理规则
场景1,由于外部内部的滑动方向不一致,我们可以根据当前滑动方向,用水平还是垂直来判断这个事件到底该交给谁来处理。
如何获得滑动方向呢?其实可以根据滑动过程的起点
和终点
在水平方向和竖直方向的距离差(或者速度差)来判断,当然也可以根据滑动路径与水平方向所形成的夹角(斜率)来判断。
场景2,由于外部与内部的滑动方向一致,那么肯定就不能根据滑动角度、距离差或者速度差来判断。这时就必须通过业务需求来进行判断,比如:在某一状态下,此时必须使用外部View滑动,而当这种状态消失时,必须使用内部View滑动,根据业务需求得出对应的处理规则,有了处理规则就可以进行下一步的处理。
多层可滑动View嵌套的场景,它和场景2处理规则一样,需要根据业务需求得出对应的处理规则,然后再通过处理规则处理。
3.滑动冲突的解决方式
上面我们只描述了典型的滑动冲突场景,但是没有说怎么解决。
接下来我们一起来看看怎么解决这些滑动冲突,场景1是最经典的一种滑动冲突,所以我们拿它下手,得到通用的解决方案,然后场景2以及多层嵌套都不在话下。
其实,不得不说…
外部拦截法
一听名字就知道,这种拦截方式是父View根据需求对事件进行拦截,所以是否拦截的逻辑就放在父View
的onInterceptTouchEvent
方法中,所以我们需要重写父View
的onInterceptTouchEvent
方法:
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted =