动画多次视图会导致动画冻结



我有一个简单的动画,使视图从屏幕的一侧转到另一侧,在动画文件夹中定义为 left_to_right.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="true">
    <translate
        android:fromXDelta="-300%" android:toXDelta="360%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="3200"/>
</set>

我想要的是在屏幕上同时在屏幕上滑动多个视图,但速度不同,所以我有2个称为left_to_right_fast.xmlleft_to_right_slow.xml的XML,除了不同的持续时间外,这是完全相同的。

因此,在我的视图类中,我有这些方法来创建条纹的图像并为其动画,当动画完成时,我将其删除并进行另一个方法:

    private fun doAStripe() {
        if (!isRunning) return
        val stripe = makeStripe()
        stripeHolder.addView(stripe)
        stripe.animation.onAnimationEnd {
            (stripe.parent as ViewGroup).removeView(stripe)
            doAStripe()
        }
        stripe.animate()
    }
    private fun makeStripe(): AppCompatImageView {
        val imageView = AppCompatImageView(context)
        imageView.layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
        imageView.setImageResource(listOf(R.drawable.cp_stripe_blue, R.drawable.cp_stripe_gray, R.drawable.cp_stripe_red).random())
        imageView.clearAnimation()
        imageView.animation = AnimationUtils.loadAnimation(context, listOf(R.anim.left_to_right, R.anim.left_to_right_fast, R.anim.left_to_right_slow).random())
        imageView.x = width / 2f
        imageView.y = (0..(stripeHolder.height)).random().toFloat()
        return imageView
    }

因此,当我只调用 doAStripe()时,它可以按预期工作,屏幕上的条纹滑动并重复。

,但我希望能够同时使用多个条纹,所以我尝试连续三遍拨打doAStripe(),但是当我这样做时 - 条纹似乎是第一次在屏幕上进行动画他们不移动的重新出现,静止几秒钟,然后消失,新条纹似乎取代了它们。

因此,由于onAnimationEnd被称为...但实际上并没有发生动画,因此动画似乎正在发生。有人知道这样做的原因吗?

我的onAnimationEnd也只是这种便利扩展:

fun Animation.onAnimationEnd(callback: () -> Unit) {
    setAnimationListener(object : Animation.AnimationListener {
        override fun onAnimationRepeat(p0: Animation?) {
        }
        override fun onAnimationEnd(p0: Animation?) {
            callback()
        }
        override fun onAnimationStart(p0: Animation?) {
        }
    })
}

更新:这是一个git回购,带有演示项目显示错误

您会注意到,如果您只能致电doAStripe(),则一旦效果很好,但是将其称为多次 - 并且对几个条纹效果很好,然后开始冻结动画。

您要进行一些骇客来同时进行两个动画,但是我遵循您的存储库,我进行了测试,是的,它看起来很笨拙Handler Android中的Animation将为您处理线程,并且您的实现存在一个问题,所有这些动画都在MainThread上,这会导致Laggy。

所以我最终这样做了:

private fun doAStripe() {
    val stripe = makeStripe()
    stripeHolder.addView(stripe)
    stripe.postDelayed({
        (stripe.parent as ViewGroup).removeView(stripe)
        doAStripe()
    }, stripe.animation.duration)
    stripe.animate().withLayer()
}

它看起来冰沙,但并不快,也许您可以用anim文件控制它。

我还添加了withLayer()

它可以为您随后添加到动画的所有视图启用硬件动画。

还在您的makeStripe()方法中添加了imageView.invalidate(),以使ImageView无效。有关更多信息,您可以在有必要在视图上执行无效

时阅读此信息。

这是一个简单的演示:

https://vimeo.com/334493212

这不是最好的选择,但是,根本无法正确说明它的问题,因此,如果我有更多的时间我会更深入地检查一下,但是从现在开始,问题"冻结"已经消失了。

最新更新