【发布时间】:2022-12-11 04:42:33
【问题描述】:
我正在使用自定义动画师在两个不同的片段中使用自定义动画为两个回收器制作动画。一切正常,除了一个小问题和一个主要问题。首先,这是自定义动画师:
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.util.Log
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator
// A custom animator to animate the items in recycler view
class RecyclerAnimator : SimpleItemAnimator() {
// Never called
override fun animateRemove(viewHolder: RecyclerView.ViewHolder): Boolean {
viewHolder.itemView.animate()
.alpha(0F)
.setInterpolator(FastOutSlowInInterpolator())
.setStartDelay(200)
.setDuration(300)
.scaleY(0F)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
dispatchRemoveFinished(viewHolder)
}
})
.start()
Log.d("recycler_animation", "animate remove")
return false
}
// Called when the items appear in the list (launch, fragment change, it was created)
override fun animateAdd(viewHolder: RecyclerView.ViewHolder): Boolean {
val height: Int = viewHolder.itemView.measuredHeight / 3
val view = viewHolder.itemView
view.translationY = height.toFloat()
view.alpha = 0F
view.scaleY = 1F
view.animate()
.translationY(0F)
.alpha(1F)
.setInterpolator(FastOutSlowInInterpolator())
.setDuration(400)
.setStartDelay(viewHolder.bindingAdapterPosition * 50L)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
dispatchAddFinished(viewHolder)
}
})
.start()
Log.d("recycler_animation", "animate add")
return false
}
// Called when an item is being moved to another position in the adapter
override fun animateMove(
viewHolder: RecyclerView.ViewHolder,
fromX: Int, fromY: Int,
toX: Int, toY: Int
): Boolean {
val item = viewHolder.itemView
item.y = fromY.toFloat()
val verticalMovement = if (toY > fromY)
(toY - fromY).toFloat() - (item.measuredHeight)
else (fromY - toY).toFloat() - (item.measuredHeight)
item.animate()
.translationY(verticalMovement)
.setDuration(300)
.setInterpolator(FastOutSlowInInterpolator())
.setStartDelay(200)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
dispatchMoveFinished(viewHolder)
}
})
.start()
Log.d("recycler_animation", "animate move")
return false
}
// Called when an item changes its data
override fun animateChange(
oldHolder: RecyclerView.ViewHolder,
newHolder: RecyclerView.ViewHolder,
fromLeft: Int, fromTop: Int,
toLeft: Int, toTop: Int
): Boolean {
newHolder.itemView.alpha = 0F
val oldAnimation = oldHolder.itemView.animate()
.alpha(0F)
.setInterpolator(FastOutSlowInInterpolator())
.setDuration(300)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
dispatchChangeFinished(oldHolder, true)
}
})
val newAnimation = newHolder.itemView.animate()
.alpha(1F)
.setInterpolator(FastOutSlowInInterpolator())
.setDuration(300)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
dispatchChangeFinished(newHolder, false)
}
})
oldAnimation.start()
newAnimation.start()
Log.d("recycler_animation", "animate change")
return false
}
// Called when an item is deleted from the adapter
override fun animateDisappearance(
viewHolder: RecyclerView.ViewHolder,
preLayoutInfo: ItemHolderInfo,
postLayoutInfo: ItemHolderInfo?
): Boolean {
viewHolder.itemView.animate()
.alpha(0F)
.setInterpolator(FastOutSlowInInterpolator())
.setDuration(400)
.setStartDelay(100)
.scaleY(0F)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
dispatchRemoveFinished(viewHolder)
viewHolder.itemView.alpha = 1F
viewHolder.itemView.scaleY = 1F
}
})
.start()
Log.d("recycler_animation", "animate disappearance")
return false
}
override fun runPendingAnimations() {
Log.d("recycler_animation", "pending animations")
}
override fun endAnimation(viewHolder: RecyclerView.ViewHolder) {
Log.d("recycler_animation", "end animation")
val item = viewHolder.itemView
item.alpha = 1F
item.translationY = 0F
item.scaleY = 1F
}
override fun endAnimations() {
Log.d("recycler_animation", "end animation no arg")
}
override fun isRunning(): Boolean {
return false
}
}
- 首先,主要问题:我在其中一个回收器视图中使用了两种不同的 viewholder 布局,当元素移动时 (animateMove),较短的元素在向上或向下移动时都被移动到错误的位置。我的猜测是“测量的高度”是错误的,但我不知道为什么。 (这个问题可以在 gif 的第一部分观察到)
- 其次,小问题:因为我使用延迟使项目逐渐出现,所以当将项目添加回列表时,如果项目在上部动画没有延迟,而如果项目在列表中下半部分,动画根据其在列表中的位置延迟开始。 (这个问题可以在 gif 的第二部分观察到)
非常感谢任何帮助,因为我已经接近预期的效果
【问题讨论】:
标签: android animation android-recyclerview animator