瀑布流布局切Tab跳跃问题原因及两种解决方案

2,022 阅读2分钟

我开源了一个方便RecyclerView吸顶的Android库,欢迎您访问github.com/lizijin/Sti…,如果您使用本库,请提出您的宝贵意见。

它目前支持以下功能:

  1. 支持单类型吸顶功能
  2. 支持多类型吸顶功能
  3. 支持开启和关闭吸顶功能
  4. 支持指定位置吸顶功能
  5. 支持设置吸顶偏移量
  6. 支持自定义RecyclerView上Item吸顶边界自定义
  7. 可以无缝配合AppBarLayout

1. 问题描述

最近在做一个购物车+推荐商品功能。结合 RecyclerView StaggeredGridLayoutManager,完成瀑布流样式布局。完成之后,发现切换TAB,回到购物车页面后,页面会有些许的偏移。如下图。本来"洽洽香瓜子的价格 ¥9.90"紧贴TAB栏。再切换完TAB重新回来后,"洽洽香瓜子的价格 ¥9.90"字样竟然不见了。

发现此问题后,首先回滚到之前使用GridLayoutManager布局的代码。运行发现,GridLayoutManager并无此问题。看来问题的罪魁祸首是StaggeredGridLayoutManager。

2. 问题分析

2.1 购物车页面发生了偏移,那么必定调用了StaggeredGridLayoutManager的fill方法。

2.2 fill方法会调用到layoutDecoratedWithMargins方法,给RV上的View布局

2.3 layoutDecorateWithMargins中otherStart,start,otherEnd,end参数分别表示布局的left,top,right,bottom。既然发生了偏移,说明start,end参数发生了改变。start赋值处如下StaggeredGridLayoutManager#fill方法中

2.4 StaggeredGridLayoutManager#getMaxEnd方法中

2.5 StaggeredGridLayoutManager#Span#getEndLine方法中

会判断mCachedEnd 是否被置为无效。如果被置为无效那么会重新计算View的top位置。好像找到问题所在了。那么mCachedEnd在哪里被赋值成INVALID_LINE呢。找寻一番发现

2.6 StaggeredGridLayoutManager#Span#invalidateCache方法中

2.7 找寻invalidateCache方法被谁调用了

2.8 StaggeredGridLayoutManager#Span#clear方法中

2.9 找寻clear方法被谁调用了

2.10 StaggeredGridLayoutManager#onDetachedFromWindow方法如下

2.11 由此可见,切换TAB的时候触发了View的onDetachedFromWindow方法,从而清空了StaggeredGridLayoutManager中所有布局的基准线,EndLine。重新返回购物车界面,会将当前RecyclerView中的可见的第一项View从0开始重新布局,导致了偏移。由于GridLayoutManager没有发现偏移。我们可以对比一下他们的onDetachedFromWindow方法实现。

3. 解决方案

解决方案一:重写StaggeredGridLayoutManager的onDetachedFromWindow。nothing to do

解决方案二:使用StaggeredGridLayoutManager的SavedState。由代码可见,SavedState会保存瀑布流布局的参数。那么我们可以在onDetachedFromWindow被调用之前调用onSaveInstanceState方法,在onAttachedToWindow中调用

最后效果如下