我有一个简单的动画,它使视图从屏幕的一侧转到另一侧,并且在动画文件夹中将其定义为c
:
left_to_right.xml
我想要的是让多个视图同时在屏幕上滑动但速度不同,因此我还有2个名为<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>
和left_to_right_fast.xml
的xml,它们完全相同,除了不同之处持续时间。
因此,在我的视图类中,我具有以下方法来创建条纹图像并对其进行动画处理,动画完成后,我将其删除并制作另一个图像:
left_to_right_slow.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()
3次,但是当我这样做时-条纹似乎都在整个屏幕上动起来了第一次,但当它们重新出现时不动时,请静坐几秒钟,然后消失,并出现新的条纹来代替它们。
所以好像动画正在发生,因为doAStripe()
被调用了……但是实际上并没有发生。有人知道原因吗?
我的onAnimationEnd
就是这个方便的扩展名:
onAnimationEnd
更新:Here is a git repo with a demo project showing the bug
如果您使onCreate仅在效果很好的情况下调用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?) {
}
})
}
,但会不止一次地调用它,则您会注意到它-在几个条纹上效果很好,然后开始冻结动画。
答案 0 :(得分:1)
您需要做一点技巧来使两个动画同时运行,但是我很好地遵循了您的存储库并进行了测试,是的,它看起来很滞后,如果您将Animation
控制在Handler
Android
将为您处理线程,而您的实现存在一个问题,所有这些动画都在MainThread
上,这会导致延迟。
所以我最终这样做了:
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()
它为随后添加到动画中的所有视图启用硬件动画。
还在您的imageView.invalidate()
方法中添加了makeStripe()
,以使ImageView
无效。有关更多信息,您可以阅读此When it's necessary to execute invalidate on a view
这是一个简单的演示,外观:
这不是最好的选择,但是,它本身的问题根本无法正确说明,因此,如果我有更多时间,我会更深入地检查一下,但是从现在开始,“冻结”。