-
当手指触摸屏幕时,记录位置,滑动后,判断是横向竖向,只判断一次
-
如果是上下滑动,则判断是触发最外层 LinearLayout 的滑动,还是触发 RecyclerView 的自身滑动。
-
触发自身的滑动就是调用自己的
scrollBy(0,dy)
,注意 此时的事件还是会往下传递到 RecyclerView ,但是由于相对于 RecyclerView 自身来说滑动差值很小,视觉上可忽略。 -
不触发自身的滑动就会直接分发下去,此时 RecyclerView 自身来说竖向(
dy
)差值变化较大,正常滑动。 -
出现问题时,用户的手先触发左右滑动,这时候由于 RecyclerView 父布局 ViewPager 中的一些临界判断没被触发,所以没拦截事件,事件还是到了 RecyclerView 中,此时如果再次上下滑动,由于1中的判断单次滑动周期内只触发了一次,还被认为是左右滑动事件,所以 LinearLayout 布局本身没有滚动,但是 RecyclerView 正常响应滚动,导致的出现滑动偏差。
==================================================================
问题分析的差不多了,其实本来也就结束了,但是惊喜的发现原来这个自定义的滑动布局是扩展自开源库:https://github.com/cpoopc/ScrollableLayout
但是已经长时间没人维护了。不过通过这个原始的库。可以看到核心逻辑还是一致的,经过调试编译发现,确实这个库也同样存在这个问题,那就基于此库着手试着解决一下吧。
开源库的原本代码:
根据分析就是在图中 else
中其实又触发了上下滑动逻辑,而外层的自定义 LinearLayout 布局没有跟随滑动导致的。那我们是不是可以在里面加个判断,除去真正的左右滑动逻辑(ViewPager事件),剩下的事件就是触发 RecylcerView 滑动的了(相当于过滤了横向的,留下的竖向的),我们再次判断外层的自定义 LinearLayout 布局是否需要联动,如果需要再次联动就好了。
站在巨人肩膀上,系统控件的处理一般都可以借鉴,源码之下,一切清晰,横向的可以参考 ViewPager 的事件拦截,竖向的可以参考 RecyclerView 的事件处理逻辑。分析两个控件的 onIntercepetTouchEvent()
, 拿到其核心的判断是否响应滑动的逻辑为我们所用。
ViewPager 相关源码:
核心拦截逻辑:
-
如果横向上有可滑动的子 View ,就不拦截,让子 View 去处理
-
横向的滑动超过临界值
mTouchSlop
,并且大于竖向滑动距离的2倍,进行拦截
我们需要把相关的判断代码都 copy 过来,然后加入到我们自定义 LinearLayout 中
此时进行 Log 调试发现还是有问题, 原来 ViewPager 中判断了是否是子 View 消费事件,这里我们不能照搬过来,我们要取反,即如果当前自定义的 LinearLayout 中有横向可滑动的 View,我们的 isHorizontalDrag
方法应该返回 true
。
修改后的代码:
到此横向判断的过滤条件写好了。下面看竖向的 RecyclerView 的拦截代码,非常简单:
当竖向可滑动并且差值 dy
大于临界值 mTouchSlop
时,即响应事件。
经运行测试发现问题已经解决。
================================================================
最后
在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
3dJcmfy-1715125413716)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!