开门见山,最近在做一个购物车+推荐商品功能。结合 RecyclerView StaggeredGridLayoutManager,完成瀑布流样式布局。完成之后,发现切换TAB,回到购物车页面后,页面会有些许的偏移。如下图。本来"洽洽香瓜子的价格 ¥9.90"紧贴TAB栏。再切换完TAB重新回来后,"洽洽香瓜子的价格 ¥9.90"字样竟然不见了。
发现此问题后,首先回滚到之前使用GridLayoutManager布局的代码。运行发现,GridLayoutManager并无此问题。看来问题的罪魁祸首是StaggeredGridLayoutManager。
问题分析如下:
购物车页面发生了偏移,那么必定调用了StaggeredGridLayoutManager的fill方法。
fill方法会调用到layoutDecoratedWithMargins方法,给RV上的View布局
layoutDecorateWithMargins中otherStart,start,otherEnd,end参数分别表示布局的left,top,right,bottom。既然发生了偏移,说明start,end参数发生了改变。start赋值处如下
StaggeredGridLayoutManager#fill方法中
StaggeredGridLayoutManager#getMaxEnd方法中
StaggeredGridLayoutManager#Span#getEndLine方法中
会判断mCachedEnd 是否被置为无效。如果被置为无效那么会重新计算View的top位置。好像找到问题所在了。那么mCachedEnd在哪里被赋值成INVALID_LINE呢。找寻一番发现
StaggeredGridLayoutManager#Span#invalidateCache方法中
找寻invalidateCache方法被谁调用了
StaggeredGridLayoutManager#Span#clear方法中
找寻clear方法被谁调用了
StaggeredGridLayoutManager#onDetachedFromWindow方法如下
由此可见,切换TAB的时候触发了View的onDetachedFromWindow方法,从而清空了StaggeredGridLayoutManager中所有布局的基准线,EndLine。重新返回购物车界面,会将当前RecyclerView中的可见的第一项View从0开始重新布局,导致了偏移。由于GridLayoutManager没有发现偏移。我们可以对比一下他们的onDetachedFromWindow方法实现。
那么解决方案来了。
解决方案一:重写StaggeredGridLayoutManager的onDetached。nothing to do
解决方案二:使用StaggeredGridLayoutManager的SavedState。由代码可见,SavedState会保存瀑布流布局的参数。那么我们可以在onDetachedFromWindow被调用之前调用onSaveInstanceState方法,在onAttachedToWindow中调用
解决方案二如下
最后效果如下