Java 使用逐帧动画制作transitionX动画会导致延迟

Java 使用逐帧动画制作transitionX动画会导致延迟,java,android,android-studio,animation,kotlin,Java,Android,Android Studio,Animation,Kotlin,我有一个图像视图。当用户按下按钮时,我希望我的视图设置R.drawable中的图像(每次图像不同),然后使用逐帧动画执行translationX动画。为此,我使用objectanimotor.offload(…“translationX”…)并在donstart中调用图像上的AnimationDrawable.start()(我在那里设置了动画列表)。实际上,在doOnEnd上,我在视图中放置了另一个图像(动画列表)并开始另一个动画。之后,我将图像设置为不可见,并使用translationX将其

我有一个图像视图。当用户按下按钮时,我希望我的视图设置R.drawable中的图像(每次图像不同),然后使用逐帧动画执行
translationX
动画。为此,我使用
objectanimotor.offload(…“translationX”…)
并在
donstart
中调用图像上的
AnimationDrawable.start()
(我在那里设置了动画列表)。实际上,在
doOnEnd
上,我在视图中放置了另一个图像(动画列表)并开始另一个动画。之后,我将图像设置为不可见,并使用
translationX
将其返回到起点。在真实设备和模拟器上测试它会导致动画开始时和更改图像时出现延迟。我不知道如何修理它

view.setImageResource(
            this.resources.getIdentifier(
                "${spellCasted}_anim",
                "drawable", context!!.packageName
            )
        )
        val x1 = startXposition
        val x2 = firstXdestination
        val frameAnimation = view.drawable as AnimationDrawable
        ObjectAnimator.ofFloat(
                view,
                "translationX",
                x1.toFloat(),
                x2.toFloat()
            ).apply {
                duration = 900
                interpolator = LinearInterpolator()
                doOnStart {
                    view.visibility = View.VISIBLE
                    frameAnimation.start()
                }
                doOnEnd {
                    if (hasPost(splitSpell)) { //hasPost(..) check is there additional image to translate from x2 to x2 + 20
                        frameAnimation.stop()
                        view.setImageResource(
                            context!!.resources.getIdentifier(
                                "${spellCasted}stop_anim",
                                "drawable", context!!.packageName
                            )
                        )
                        ObjectAnimator.ofFloat(
                                view, "translationX",
                                x2.toFloat(),
                                x2.toFloat() +  20f
                            )
                                .apply {
                                    duration = 1200
                                    interpolator = LinearInterpolator()
                                    doOnStart {
                                        val frameAnimationStop =
                                            view.drawable as AnimationDrawable
                                        frameAnimationStop.start()
                                    }
                                    doOnEnd {
                                        setDefault(view, x1, isEnemy) //returns view to startPos
                                    }
                                    start()
                                }
                    } else {
                        setDefault(view, x1, isEnemy)//returns view to startPos
                    }
                }
                start()
            }

如果查看javadoc中的
imageView.setImageResource
,您会看到它说它将导致延迟中断,因为它将图像加载到UI线程上

我想你可以通过在背景中预加载下一个可绘制图形来解决这个问题。我没有尝试过这个,因为我不使用动画绘图工具,所以如果它不能治愈打嗝,请提前道歉

协同程序将使设置和保持有序更加容易。您可以从创建一个函数开始,该函数不需要嵌套的Animator回调:

suspend fun Animator.runToCompletion(): Unit = suspendCoroutine { cont ->
    doOnEnd { cont.resume(Unit) }
    start()
}
然后,当您启动动画时,您可以开始在背景中加载下一个可绘制图形,希望在您需要显示它的时候它已经准备好:

val cxt = requireContext() // one source of failure if context is null

lifecycleScope.launch {

    // Start loading the second animation in a background thread
    val spellStopAnimationJob: Deferred<AnimationDrawable> = async(Dispatchers.Default) {
        cxt.getDrawable(ctx.resources.getIdentifier(
            "${spellCasted}stop_anim",
            "drawable", ctx.packageName
        ) as AnimationDrawable
    }

    view.setImageResource(
       resources.getIdentifier(
                "${spellCasted}_anim",
                "drawable", cxt.packageName
            )
    )
    val x1 = startXposition
    val x2 = firstXdestination
    val initialAnimation = view.drawable as AnimationDrawable
        .apply { start() }
    view.visibility = View.VISIBLE
    ObjectAnimator.ofFloat(
        view,
        "translationX",
        x1.toFloat(),
        x2.toFloat()
    ).apply {
        duration = 900L
        interpolator = LinearInterpolator()
    }.runToCompletion()

    if (hasPost(splitSpell)) { //hasPost(..) check is there additional image to translate from x2 to x2 + 20
        initialAnimation.stop()

        // Wait for the animation to be loaded (hopefully it's already done so no hiccup)
        val stopAnimation = spellStopAnimationJob.await()
            .apply { start() }
        view.setImageDrawable(stopAnimation)
        ObjectAnimator.ofFloat(
            view, "translationX",
            x2.toFloat(),
            x2.toFloat() + 20f
        ).apply {
            duration = 1200
            interpolator = LinearInterpolator()
        }.runToCompletion()
    }

    setDefault(view, x1, isEnemy)//returns view to startPos
}
val cxt=requireContext()//如果上下文为空,则是失败的一个原因
生命周期望远镜发射{
//开始在背景线程中加载第二个动画
val spellStopAnimationJob:Deferred=async(Dispatchers.Default){
getDrawable(ctx.resources.getIdentifier(
“${拼写铸造}停止动画”,
“可牵引”,ctx.packageName
)作为动画绘制
}
view.setImageResource(
resources.getIdentifier(
“${拼写铸造}\u anim”,
“可牵引”,cxt.packageName
)
)
val x1=起始位置
val x2=第一个xDestination
val initialAnimation=view.drawable作为AnimationDrawable
.apply{start()}
view.visibility=view.visibility
ObjectAnimator.offload(
看法
“translationX”,
x1.toFloat(),
x2.toFloat()
).申请{
持续时间=900升
插值器=线性插值器()
}.runToCompletion()文件
如果(hasPost(splitSpell)){//hasPost(..)检查是否有其他图像需要从x2转换到x2+20
initialAnimation.stop()
//等待加载动画(希望已经加载了,不要打嗝)
val stopAnimation=spellStopAnimationJob.await()
.apply{start()}
view.setImageDrawable(停止动画)
ObjectAnimator.offload(
视图,“translationX”,
x2.toFloat(),
x2.toFloat()+20f
).申请{
持续时间=1200
插值器=线性插值器()
}.runToCompletion()文件
}
setDefault(view,x1,isEnemy)//将视图返回给startPos
}

顺便说一下,行
x2.toFloat()在不同的设备上运行此操作时,+20f
会让您陷入困境,因为您硬编码的偏移量是以像素为单位,而不是以倾角为单位。您应该以倾角为单位指定数字,然后乘以
resources.displayMetrics.density
,将其转换为像素单位。

图像的变化频率是多少?您是否在图像继续变化时进行了更改nues移动到其目标X位置?查看您的代码以了解如何调整它以避免打嗝真的很有帮助。@Tenfour04谢谢您的回答,我添加了这个动画功能,现在您可以检查了。@Tenfour04在我设置为查看的每个动画列表中大约有5-9帧。非常感谢!我阅读了文档,您完全满意哈!我有个主意。也许我可以将资源预加载到可绘制的只是使用它?码头说SimimaDeDRAWEABLE并没有停止U.I.也许。你只需要小心不要超过分配的堆内存,如果图像是大的或有很多。安卓是非常吝啬堆内存。如果你是一个游戏,有很多图像,你应该考虑OpenGL(或游戏引擎)因此图像作为纹理加载到GPU内存中。当然GPU也有内存限制,但它要高得多。