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中调用
最后效果如下