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

Многие 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 и spring для анимации и ее прерывание.

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

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

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

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

Более подробную информацию см. в разделе «Смягчение» .

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

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

Необязательно указывать значения при 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"
)

Плавная анимация между ключевыми кадрами с помощью keyframesWithSplines

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

val offset by animateOffsetAsState(
    targetValue = Offset(300f, 300f),
    animationSpec = keyframesWithSpline {
        durationMillis = 6000
        Offset(0f, 0f) at 0
        Offset(150f, 200f) atFraction 0.5f
        Offset(0f, 100f) atFraction 0.7f
    }
)

Сплайновые ключевые кадры особенно полезны для 2D-перемещения объектов на экране.

В следующих видеороликах показаны различия между keyframes и keyframesWithSpline с учетом того же набора координат x, y, которому должна следовать окружность.

keyframes keyframesWithSplines

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

Повторите анимацию с помощью 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 (конец), указывающее текущую точку в анимации.

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

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 , которые охватывают большинство случаев использования. См. Speed ​​- 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 :

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