StaggeredGridLayoutManager 简单介绍
RecyclerView中布局管理器,主要用于瀑布流的实现。
StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
主要有两个参数
- 行数/列数,取决于第二行参数
- 垂直还是水平方向
意外之喜
当我简单的给RecyclerView设置StaggeredGridLayoutManager 之后,发现下面的问题
当滑动到最上面的时候,左右两列发生交换,这本质是发生了重新排序
初步解决方案
查询了一下网上资料 解决方案
recyclerView?.layoutManager =
StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL).apply {
gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE //防止Item互换
}
gapStrategy有两种
GAP_HANDLING_NONE: 什么也不处理GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS(默认值): 当滚动状态变化时,StaggeredGrid 会检查是否因为元素跨度过大导致出现空隙,如果发现空隙,它会重新布局,并使用动画元素移动到正确位置
使用上面的代码,禁止GAP处理又发现一个问题
我们捋一下这个问题,GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS 的重排序导致了item发生交换,禁用重排序有导致顶部空白的问题。
为什么重排序导致了item发生交换和空白?
如图所示,向下滑动的时候,排列顺序如下,如果滑动到底部,在向上滑动,会发现,3的位置从原来的第1列跑到第二列,2的位置从原来的第2列跑到在第一列。
如果不进行重新排序,就会导2和1 顶部空白,如果重新排序,就会再次根据空隙,把2的位置放到第2列区,所以视觉上,你会看到左右交换了一下。
最终方案解决
- 禁用重排序
recyclerView?.layoutManager =
StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL).apply {
gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE //防止Item互换
}
2. 到首页的时候要求重新布局
/**
* 修复瀑布流顶部空白问题和间距错乱问题
* 在onScrolled中调用
*/
fun fixWaterfallFlowBlank(recyclerView: RecyclerView) {
val layoutManager = recyclerView.layoutManager
if (layoutManager !is StaggeredGridLayoutManager) {
return
}
try {
val firstVisibleItemPositions = IntArray(layoutManager.spanCount)
layoutManager.findFirstVisibleItemPositions(firstVisibleItemPositions)
val firstVisibleItemPosition = firstVisibleItemPositions[0]
if (firstVisibleItemPosition <= 1) { //滚动到顶部,瀑布流2列,position可能是0或者1
layoutManager.invalidateSpanAssignments() //重新布局
recyclerView.invalidateItemDecorations() //间距错乱问题
}
} catch (e: Exception) {
Logger.e(e)
}
}