Анимация нескольких видов приводит к зависанию анимации - PullRequest
1 голос
/ 03 мая 2019

У меня есть простая анимация, которая заставляет представление переходить с одной стороны экрана на другую, и оно определено в папке 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 xmls с именами left_to_right_fast.xml и left_to_right_slow.xml, которые точно такие же, за исключением другой продолжительности.

Так что в моем классе просмотра Iу меня есть эти методы для создания изображения полосы и его анимации, а когда анимация завершена, я удаляю ее и создаю еще один:

    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-репозиторий с демонстрационным проектом, показывающим ошибку

вы заметите, что если вы сделаете onCreate, то позвоните только doAStripe(), как только он отлично заработает, но вызовите его несколько раз - и он хорошо работает для пары полос, затем начинает останавливать анимацию.

1 Ответ

1 голос
/ 06 мая 2019

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

Это простая демонстрация того, как это выглядит:

https://vimeo.com/334493212

Это не лучший вариант, но, собственно, проблема сама по себе не сформулирована правильно, поэтому, если у меня будет больше времени, я пойду глубже, чтобы проверить это, но с этого момента проблема " заморозка "ушел.

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