抖音首页右滑可进入“个人中心”页面,对于首页日活上亿的 APP 来说,这个页面的pv理论上应该不会太小。但是某些时候在此页面会出现滑动冲突的小问题,不太利于用户体验,通过反复的把玩测试,找到了必现的操作,作为一个资深的抖迷和一个非资深的 Android 开发的我,产生了钻牛角尖的想法—想看看问题是怎么产生的,以及有没有可优化的方案。
首页右滑可进入“个人中心”页面,然后在底部的 RecylerView 上先左右滑动,但是不触发它们父布局 ViewPager 的切换,然后手指不抬起,进行上下滑动,此时 RecylerView 会接收滑动事件,导致滑动错位,如下图所示:
问题明确了,接下来就是分析是如何产生的了。我通过综合分析发现,抖音用的是自定义 LinearLayout 的方式来布局 header + Viewpager + RecyclerView 的,进而通过拦截 LinearLayout 的 disptachTouchEvent
来处理的嵌套滑动。整体的滑动流程如图所示:
scrollBy(0,dy)
,注意 此时的事件还是会往下传递到 RecyclerView ,但是由于相对于 RecyclerView 自身来说滑动差值很小,视觉上可忽略。dy
)差值变化较大,正常滑动。问题分析的差不多了,其实本来也就结束了,但是惊喜的发现原来这个自定义的滑动布局是扩展自开源库:https://github.com/cpoopc/ScrollableLayout
但是已经长时间没人维护了。不过通过这个原始的库。可以看到核心逻辑还是一致的,经过调试编译发现,确实这个库也同样存在这个问题,那就基于此库着手试着解决一下吧。
根据分析就是在图中 else
中其实又触发了上下滑动逻辑,而外层的自定义 LinearLayout 布局没有跟随滑动导致的。那我们是不是可以在里面加个判断,除去真正的左右滑动逻辑(ViewPager事件),剩下的事件就是触发 RecylcerView 滑动的了(相当于过滤了横向的,留下的竖向的),我们再次判断外层的自定义 LinearLayout 布局是否需要联动,如果需要再次联动就好了。
站在巨人肩膀上,系统控件的处理一般都可以借鉴,源码之下,一切清晰,横向的可以参考 ViewPager 的事件拦截,竖向的可以参考 RecyclerView 的事件处理逻辑。分析两个控件的 onIntercepetTouchEvent()
, 拿到其核心的判断是否响应滑动的逻辑为我们所用。
核心拦截逻辑:
mTouchSlop
,并且大于竖向滑动距离的2倍,进行拦截我们需要把相关的判断代码都 copy 过来,然后加入到我们自定义 LinearLayout 中
此时进行 Log 调试发现还是有问题, 原来 ViewPager 中判断了是否是子 View 消费事件,这里我们不能照搬过来,我们要取反,即如果当前自定义的 LinearLayout 中有横向可滑动的 View,我们的 isHorizontalDrag
方法应该返回 true
。
到此横向判断的过滤条件写好了。下面看竖向的 RecyclerView 的拦截代码,非常简单:
当竖向可滑动并且差值 dy
大于临界值 mTouchSlop
时,即响应事件。
经运行测试发现问题已经解决。
简单来说,用户横向滑动时,通过增加 isHorizontalDrag() 判断是否有子 View 消费横向事件。如果有则啥也不做,如果没有,那么我们判断是不是要最外层的 LinearLayout 消费其中的竖向部分,满足条件后,自身消费事件滚动。
以上是个人对于抖音“个人中心”页面滑动冲突优化的拙见及优化方案,仅仅是自己做过简单测试,个人觉得更好的方案可以使用谷歌的嫡系 CoordinatorLayout 来处理这种嵌套滑动。 原文链接:https://juejin.cn/post/6936050349400653860
您的点赞收藏就是对我最大的鼓励! 欢迎关注我,分享Android干货,交流Android技术。 对文章有何见解,或者有何技术问题,欢迎在评论区一起留言讨论!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。