Как анимировать ImageView для перехода к случайному значению и рандомизации значения при каждом повторении в Kotlin?

#android #kotlin #animation

#Android #котлин #Анимация

Вопрос:

Я пытаюсь создать вибрирующую анимацию для просмотра изображения в Kotlin.

Вот код, с которого я начинаю:

 var randomX = Random.nextInt(-100, 100).toFloat()
var moveX = ObjectAnimator.ofFloat(imageView, View.TRANSLATION_X, randomX).apply {
  duration = 100
  repeatCount = ObjectAnimator.INFINITE

  addListener(object : Animator.AnimatorListener {
    override fun onAnimationStart(animation: Animator?) {}
    override fun onAnimationEnd(animation: Animator?) {}
    override fun onAnimationCancel(animation: Animator?) {}
    override fun onAnimationRepeat(animation: Animator?) {
      randomX = Random.nextInt(-100, 100).toFloat()
    }
  })
}

var randomY = Random.nextInt(-100, 100).toFloat()
var moveY = ObjectAnimator.ofFloat(imageView, View.TRANSLATION_Y, randomY).apply {
  duration = 100
  repeatCount = ObjectAnimator.INFINITE

  addListener(object : Animator.AnimatorListener {
    override fun onAnimationStart(animation: Animator?) {}
    override fun onAnimationEnd(animation: Animator?) {}
    override fun onAnimationCancel(animation: Animator?) {}
    override fun onAnimationRepeat(animation: Animator?) {
      randomY = Random.nextInt(-100, 100).toFloat()
    }
  })
}

var move = AnimatorSet()
move.playTogether(moveX, moveY)
move.start()
  

С чем у меня возникают проблемы, так это с изменением случайных значений и последующим обновлением анимации новыми случайными значениями при каждом повторении. Он всегда использует только начальные значения.

Ответ №1:

Ваши слушатели просто меняют эти var значения, когда анимация повторяется, анимации уже определены с исходными значениями, поэтому при цикле ничего не меняется — он просто делает то же самое снова.

Вы можете получить желаемый эффект, в основном определяя новую анимацию каждый раз — вот способ с ViewPropertyAnimator подходом:

 fun randomPosition() = Random.nextInt(-100, 100).toFloat()
fun vibrate() {
    imageView.animate()
        .translationX(randomPosition())
        .translationY(randomPosition())
        .setDuration(100)
        .withEndAction(::vibrate)
        .start()
}
  

по сути, он выполняет то же самое, затем у него есть «конечное действие», которое просто снова вызывает функцию. Поскольку он каждый раз создает новую анимацию, он захватывает новую пару случайных значений.

Вы также можете контролировать количество повторений, если хотите!

 fun vibrate(count: Int = 10) {
    if (count < 1) return
    imageView.animate()
        .translationX(randomPosition())
        .translationY(randomPosition())
        .setDuration(100)
        .withEndAction{ vibrate(count-1) }
        .start()
}
  

Это просто уменьшает количество оставшихся вибраций, пока вы не достигнете нуля и анимация не прекратится. Я использовал значение параметра по умолчанию, чтобы вы могли определить там стандартное количество вибраций и просто звонить vibrate() из любого места, которое его использует.

(Также это не рекурсивно, потому что на самом деле это не вызов функции изнутри самой себя — она делает это на более позднем этапе изнутри объекта функции, переданного аниматору. На случай, если вас это беспокоило!)