Итак, моему клиенту нужен список из 3 столбцов, в каждом из которых может быть 1, 2 или 3 столбца. Итак, у меня есть GridLayoutManager.SpanSizeLookup
.
object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return when (viewModel.adapter.list[position]) {
is Type.One -> 1
is Type.Two -> 2
is Type.Three -> 3
}
}
}
Это хорошо работает. Но с моим аниматором предметов у меня есть сбой, который я не могу показать из-за конфиденциальности клиента.
class ItemAnimator(
private val cellSize: Float
) : DefaultItemAnimator() {
private var isRunningTmp: Boolean = false
override fun animateChange(
oldHolder: RecyclerView.ViewHolder?,
newHolder: RecyclerView.ViewHolder?,
fromLeft: Int,
fromTop: Int,
toLeft: Int,
toTop: Int
): Boolean {
if (oldHolder != null && newHolder != null) {
val context: Context = newHolder.itemView.context
val startWidth: Float =
getSpanCount(oldHolder).times(cellSize).minus(context.dp2px(16f))
val startHeight: Float = context.dp2px(if (oldHolder is ThreeViewHolder) 208f else 168f)
val endWidth: Float = getSpanCount(newHolder).times(cellSize).minus(context.dp2px(16f))
val endHeight: Float = context.dp2px(if (newHolder is ThreeViewHolder) 208f else 168f)
val diffHeight: Float = endHeight.minus(startHeight)
val diffWidth: Float = endWidth.minus(startWidth)
val animator: ValueAnimator = ValueAnimator.ofFloat(0f, 100f)
val paramsOld: GridLayoutManager.LayoutParams =
oldHolder.itemView.layoutParams as GridLayoutManager.LayoutParams
paramsOld.width = endWidth.roundToInt()
paramsOld.height = endHeight.roundToInt()
oldHolder.itemView.layoutParams = paramsOld
when (newHolder) {
is OneViewHolder -> newHolder.binding.viewModel?.isSelected?.set(true)
is TwoViewHolder -> newHolder.binding.viewModel?.isSelected?.set(true)
is ThreeViewHolder -> newHolder.binding.viewModel?.isSelected?.set(true)
}
oldHolder.itemView.visibility = View.GONE
animator.addUpdateListener {
val percent: Float = (it.animatedValue as Float).div(100)
val tmpNew = newHolder.itemView.layoutParams
tmpNew.height = startHeight.plus(percent.times(diffHeight)).roundToInt()
tmpNew.width = startWidth.plus(percent.times(diffWidth)).roundToInt()
newHolder.itemView.layoutParams = tmpNew
}
animator.duration = 300
animator.addOnStartAnimation {
isRunningTmp = true
dispatchChangeStarting(oldHolder, true)
dispatchChangeStarting(newHolder, false)
}.addOnEndAnimation {
isRunningTmp = false
oldHolder.itemView.layoutParams = paramsOld
oldHolder.itemView.visibility = View.VISIBLE
newHolder.itemView.visibility = View.VISIBLE
dispatchChangeFinished(oldHolder, true)
dispatchChangeFinished(newHolder, false)
dispatchAnimationsFinished()
}
animator.start()
return true
}
return super.animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft, toTop)
}
override fun isRunning(): Boolean {
return super.isRunning() && isRunningTmp
}
private fun getSpanCount(viewHolder: RecyclerView.ViewHolder): Int {
return when (viewHolder) {
is TwoViewHolder -> 2
is ThreeViewHolder -> 3
else -> 1
}
}
}
Есть некоторые скачки, особенно когда я изменяю высоту. Не знаю, правильно ли я использую ItemAnimator.