Функция repeatable и повторение анимации

Последнее обновление: 13.04.2024

Для повторения анимации применяется класс RepeatableSpec (который реализует интерфейс AnimationSpec). Объект этого класса можно получить с помощью функции repeatable():

public fun <T> repeatable(
    iterations: Int,
    animation: DurationBasedAnimationSpec<T>,
    repeatMode: RepeatMode = RepeatMode.Restart,
    initialStartOffset: StartOffset = StartOffset(0)
): RepeatableSpec<T>

Она принимает следующие параметры:

  • iterations: количество повторений

  • animation: спецификация анимации. Можно использовать другие функции, которые возвращают DurationBasedAnimationSpec, например, функцию tween()

  • repeatMode: значение RepeatMode, которое указывает, должна ли анимация выполняться от начала до конца (значение RepeatMode.Restart) или должна выполняться в обратном порядке - от конца к началу (значение RepeatMode.Reverse)

  • initialStartOffset: смещение отностельно начала

В данном случае первые два параметра обязательные. Например, повторим анимацию 3 раза:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.repeatable
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.platform.LocalConfiguration


class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val boxWidth = 150
            val startOffset = 0
            val endOffset = LocalConfiguration.current.screenWidthDp - boxWidth

            var boxState by remember { mutableStateOf(startOffset)}

            val offset by animateDpAsState(
                targetValue = boxState.dp,
                animationSpec = repeatable(3, animation = tween(2000))
            )

            Column(Modifier.fillMaxWidth()) {
                Box(Modifier.padding(start=offset).size(boxWidth.dp).background(Color.DarkGray))

                Button({boxState = if (boxState==startOffset) {endOffset} else {startOffset} },
                    Modifier.padding(10.dp)) {
                    Text("Move", fontSize = 25.sp)
                }
            }
        }
    }
}

В данном случае по нажатию на кнопку запускается анимация, которая перемещает компонента Box от начала до конца по горизонтали, причем процесс повторяется три раза:

повторение анимации и repeatable в Jetpack Compose на Kotlin в Android

Здесь в начале определяем некоторые значения, которые будут вычисляться для изменения позиции компонента Box:

val boxWidth = 150      // ширина компонента
val startOffset = 0   // начальная позиция
val endOffset = LocalConfiguration.current.screenWidthDp - boxWidth // конечная позиция

То есть наш Box имеет ширину boxWidth и будет перемещаться от позиции startOffset до endOffset.

Далее определяем состояние, от которого будет зависеть позиция компонента Box:

var boxState by remember { mutableStateOf(startOffset)}

Затем определяем анимацию позиции Box с помощью функции animateDpAsState()

val offset by animateDpAsState(
    targetValue = boxState.dp,
    animationSpec = repeatable(3, animation = tween(2000))
)

Параметр targetValue на основании boxState определяет позицию, к которой надо выполнить переход. А параметру animationSpec присваивается значение функции repeatable(). Первый аргумент функции - число 3 указывает на количество повторений. А параметру animation получает результат функции tween(), которая устанавливает время анимации - 2000 миллисекунд.

Результат функцит animateDpAsState() передаем в переменну offset и далее используем ее для установки отступа от начала контейнера для компонента Box:

Box(Modifier.padding(start=offset)      // устанавливаем отступ
        .size(boxWidth.dp)
        .background(Color.DarkGray))

И для запуска анимации на кнопку Move вешаем обработчик нажатия, который переключает значение boxState со startOffset на endOffset и обратно.

Button({boxState = if (boxState==startOffset) {endOffset} else {startOffset} },

Однако при выполнения анимации после ее завершения компонент Box резко перемещается на начальную позицию и с нее уже начинает вторую итерацию анимации. Параметр repeatMode при значении RepeatMode.Reverse позволяет задать воспроизведение анимации в обратном порядке:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.repeatable
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.platform.LocalConfiguration


class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val boxWidth = 150
            val startOffset = 0
            val endOffset = LocalConfiguration.current.screenWidthDp - boxWidth

            var boxState by remember { mutableStateOf(startOffset)}

            val offset by animateDpAsState(
                targetValue = boxState.dp,
                // 3 раза повторяем анимацию в течение 2 секунд, повторяем в обратном порядке
                animationSpec = repeatable(3, animation = tween(2000), repeatMode = RepeatMode.Reverse)
            )

            Column(Modifier.fillMaxWidth()) {
                Box(Modifier.padding(start=offset).size(boxWidth.dp).background(Color.DarkGray))

                Button({boxState = if (boxState==startOffset) {endOffset} else {startOffset} },
                    Modifier.padding(10.dp)) {
                    Text("Move", fontSize = 25.sp)
                }
            }
        }
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850