【问题标题】:Recylerview custom animator, issues on moving and adding elementsRecyclerview 自定义动画师,移动和添加元素的问题
【发布时间】: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


    【解决方案1】:

    在主要问题上,可能是由于 measuredHeight 与高度。

    来自 View 页面。 “一个视图实际上拥有两对宽度和高度值。” “测量的宽度和测量的高度。这些尺寸定义了视图的大小”“宽度和高度。这些尺寸定义了屏幕上视图的实际大小”因为您正在调用 measuredHeight,最终项目的实际高度布局可能不同意。

    关于小问题,您是否尝试过从动画函数返回“true”?文档中的措辞确实令人困惑,但可以解释为“如果请求调用 runPendingAnimations,则为 true,如果在稍后调用 runPendingAnimations 时一起启动所有动画,则为 false”

    【讨论】:

      猜你喜欢
      • 2021-03-31
      • 1970-01-01
      • 2017-02-05
      • 1970-01-01
      • 1970-01-01
      • 2013-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多