Создание переходной анимации с покадровой анимацией вызывает лаги - PullRequest
0 голосов
/ 17 февраля 2020

У меня есть ImageView. Когда пользователь нажимает кнопку, я хочу, чтобы мой вид установил изображение из R.drawable (каждый раз, когда изображение отличается), а затем сделал translationX анимацию с покадровой анимацией. Для этого я использую ObjectAnimtor.OfFloat(..."translationX"...), а в doOnStart я вызываю 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()
            }

1 Ответ

0 голосов
/ 17 февраля 2020

Если вы посмотрите на javado c для imageView.setImageResource, вы увидите, что он вызывает сбой задержки, поскольку загружает изображение в поток пользовательского интерфейса.

Я думаю, вы можете исправить это путем предварительной загрузки вашего следующего drawable в фоновом режиме. Я не пробовал этого, потому что я не работаю с анимационными рисованными объектами, поэтому заранее извиняюсь, если это не излечит икоту.

Сопрограммы упростят настройку и поддержание порядка. Вы можете начать с создания функции, которая устраняет необходимость использования вложенных обратных вызовов 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
}

Кстати, эта строка x2.toFloat() + 20f будет мешать вам при запуске этого на разных устройствах, так как вы жестко кодируете смещение в пикселях вместо DIP-блоков. Вы должны указать число в единицах DIP и умножить на resources.displayMetrics.density, чтобы преобразовать его в пиксельные единицы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...