android - 为多个视图设置动画会导致动画冻结
问题描述
我有一个简单的动画,使视图从屏幕的一侧转到另一侧,并在 anim 文件夹中定义为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 个 xml left_to_right_fast.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()
它按预期工作时,一条条纹滑过屏幕并重复。
但是我希望能够同时出现多个条纹,所以我尝试doAStripe()
连续调用 3 次,但是当我这样做时 - 第一次条纹似乎都在屏幕上显示动画,但是当它们重新出现时它们不会不动,静坐几秒钟然后消失,新的条纹出现代替它们。
所以看起来动画正在发生,因为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()
在它运行良好时调用 onCreate,但不止一次调用它 - 它适用于几个条纹然后开始冻结动画。
解决方案
你做了一些小技巧来让两个动画同时运行,但是我遵循了你的存储库并进行了测试,是的,它看起来很滞后,问题是,如果你控制Animation
内部 aHandler
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
. 有关更多信息,您可以阅读此当需要对视图执行无效时
这是一个简单的演示它的外观:
这不是最好的选择,但是,它本身的问题根本没有正确说明,所以,如果我有更多时间,我会更深入地检查它,但从现在开始,“冻结”的问题是走了。
推荐阅读
- python - 错误“电子邮件没有属性编码”在 python 中发送电子邮件
- python - 如何从路径字符串的容器中删除,重复的文件名及其不同的路径?
- java - 为什么打印 char[] 数组不打印任何输出?
- delphi - 将组件定义为具有与其 ClassName 不同的名称前缀(减去“T”)
- sql-server - SQL Server 中多个小数点的数据类型
- java - 提高使用多个微服务填充材料爆炸树的性能的方法
- mongodb - 如何在猫鼬中插入自动增量编号
- html - html/css 或 boostrap 中的导航搜索栏
- c# - 如何在.net中设置可变时间秒精度格式?
- java - Gmail API,撤销后获取新的访问令牌