Настройка анимации

Многие API-интерфейсы анимации обычно принимают параметры для настройки своего поведения.

Настройте анимацию с помощью параметра AnimationSpec

Большинство API-интерфейсов анимации позволяют разработчикам настраивать характеристики анимации с помощью необязательного параметра AnimationSpec .

val alpha: Float by animateFloatAsState(
    targetValue = if (enabled) 1f else 0.5f,
    // Configure the animation duration and easing.
    animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing),
    label = "alpha"
)

Существуют разные виды AnimationSpec для создания разных типов анимации.

Создание анимации на основе физики с помощью spring

spring создает основанную на физике анимацию между начальными и конечными значениями. Он принимает 2 параметра: dampingRatio и stiffness .

dampingRatio определяет, насколько упругой должна быть пружина. Значение по умолчанию — Spring.DampingRatioNoBouncy .

Рисунок 1. Настройка различных коэффициентов демпфирования пружины.

stiffness определяет, насколько быстро пружина должна двигаться к конечному значению. Значение по умолчанию — Spring.StiffnessMedium .

Рисунок 2. Настройка различной жесткости пружины

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = spring(
        dampingRatio = Spring.DampingRatioHighBouncy,
        stiffness = Spring.StiffnessMedium
    ),
    label = "spring spec"
)

spring может обрабатывать прерывания более плавно, чем типы AnimationSpec на основе продолжительности, поскольку он гарантирует непрерывность скорости при изменении целевого значения во время анимации. spring используется в качестве AnimationSpec по умолчанию во многих API анимации, таких как animate*AsState и updateTransition .

Например, если мы применим конфигурацию spring к следующей анимации, которая управляется касанием пользователя, то при прерывании анимации по мере ее выполнения вы увидите, что использование tween не работает так гладко, как использование spring .

Рисунок 3. Установка спецификаций tween vs spring для анимации и ее прерывание.

Анимация между начальным и конечным значениями с помощью кривой замедления с помощью tween

tween анимирует между начальным и конечным значениями в течение указанной durationMillis используя кривую замедления. tween — это сокращение от слова «между» — поскольку оно происходит между двумя значениями.

Вы также можете указать delayMillis чтобы отложить начало анимации.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = tween(
        durationMillis = 300,
        delayMillis = 50,
        easing = LinearOutSlowInEasing
    ),
    label = "tween delay"
)

См. раздел «Ускорение» для получения дополнительной информации.

Анимация до определенных значений в определенные моменты времени с помощью keyframes

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

Необязательно указывать значения для 0 мс и времени продолжительности. Если вы не укажете эти значения, по умолчанию они будут равны начальному и конечному значениям анимации соответственно.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = keyframes {
        durationMillis = 375
        0.0f at 0 using LinearOutSlowInEasing // for 0-15 ms
        0.2f at 15 using FastOutLinearInEasing // for 15-75 ms
        0.4f at 75 // ms
        0.4f at 225 // ms
    },
    label = "keyframe"
)

Повторите анимацию с помощью repeatable

repeatable многократно запускает анимацию на основе продолжительности (например, tween или keyframes ), пока не достигнет указанного количества итераций. Вы можете передать параметр repeatMode , чтобы указать, должна ли анимация повторяться, начиная с начала ( RepeatMode.Restart ) или с конца ( RepeatMode.Reverse ).

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = repeatable(
        iterations = 3,
        animation = tween(durationMillis = 300),
        repeatMode = RepeatMode.Reverse
    ),
    label = "repeatable spec"
)

Повторяйте анимацию бесконечно с помощью infiniteRepeatable

infiniteRepeatable похож на repeatable , но повторяется бесконечное количество итераций.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = infiniteRepeatable(
        animation = tween(durationMillis = 300),
        repeatMode = RepeatMode.Reverse
    ),
    label = "infinite repeatable"
)

В тестах с использованием ComposeTestRule анимация с использованием infiniteRepeatable не запускается. Компонент будет визуализирован с использованием начального значения каждого анимированного значения.

Немедленно привязать к конечному значению с помощью snap

snap — это специальный AnimationSpec , который немедленно переключает значение на конечное значение. Вы можете указать delayMillis , чтобы задержать начало анимации.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = snap(delayMillis = 50),
    label = "snap spec"
)

Установите пользовательскую функцию замедления

Операции AnimationSpec на основе продолжительности (такие как tween или keyframes ) используют Easing для настройки доли анимации. Это позволяет анимационному значению ускоряться и замедляться, а не двигаться с постоянной скоростью. Дробь — это значение от 0 (начало) до 1,0 (конец), указывающее текущую точку анимации.

На самом деле замедление — это функция, которая принимает дробное значение от 0 до 1,0 и возвращает число с плавающей запятой. Возвращаемое значение может находиться за пределами границы, обозначая превышение или недостижение. Пользовательское замедление можно создать, как показано в коде ниже.

val CustomEasing = Easing { fraction -> fraction * fraction }

@Composable
fun EasingUsage() {
    val value by animateFloatAsState(
        targetValue = 1f,
        animationSpec = tween(
            durationMillis = 300,
            easing = CustomEasing
        ),
        label = "custom easing"
    )
    // ……
}

Compose предоставляет несколько встроенных функций Easing , которые подходят для большинства случаев использования. См . раздел «Скорость — Material Design» для получения дополнительной информации о том, какое Easing использовать в зависимости от вашего сценария.

Анимация пользовательских типов данных путем преобразования в AnimationVector и обратно.

Большинство API-интерфейсов Compose анимации поддерживают Float , Color , Dp и другие базовые типы данных в качестве значений анимации по умолчанию, но иногда вам необходимо анимировать другие типы данных, включая ваши собственные. Во время анимации любое значение анимации представляется как AnimationVector . Значение преобразуется в AnimationVector и наоборот с помощью соответствующего TwoWayConverter , чтобы основная система анимации могла обрабатывать их единообразно. Например, Int представлен как AnimationVector1D , содержащий одно значение с плавающей запятой. TwoWayConverter для Int выглядит следующим образом:

val IntToVector: TwoWayConverter<Int, AnimationVector1D> =
    TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })

По сути, Color представляет собой набор из 4 значений: красного, зеленого, синего и альфа, поэтому Color преобразуется в AnimationVector4D , который содержит 4 значения с плавающей запятой. Таким образом, каждый тип данных, используемый в анимации, преобразуется в AnimationVector1D , AnimationVector2D , AnimationVector3D или AnimationVector4D в зависимости от его размерности. Это позволяет независимо анимировать различные компоненты объекта, каждый со своим собственным отслеживанием скорости. Доступ к встроенным преобразователям базовых типов данных можно получить с помощью таких преобразователей, как Color.VectorConverter или Dp.VectorConverter .

Если вы хотите добавить поддержку нового типа данных в качестве значения анимации, вы можете создать свой собственный TwoWayConverter и предоставить его API. Например, вы можете использовать animateValueAsState для анимации вашего пользовательского типа данных следующим образом:

data class MySize(val width: Dp, val height: Dp)

@Composable
fun MyAnimation(targetSize: MySize) {
    val animSize: MySize by animateValueAsState(
        targetSize,
        TwoWayConverter(
            convertToVector = { size: MySize ->
                // Extract a float value from each of the `Dp` fields.
                AnimationVector2D(size.width.value, size.height.value)
            },
            convertFromVector = { vector: AnimationVector2D ->
                MySize(vector.v1.dp, vector.v2.dp)
            }
        ),
        label = "size"
    )
}

Следующий список включает некоторые встроенные VectorConverter :

{% дословно %} {% дословно %} {% дословно %} {% дословно %}