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

Многие 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 создаёт физическую анимацию между начальным и конечным значениями. Она принимает два параметра: 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 , охватывающих большинство сценариев. Подробнее о том, какие функции Easing следует использовать в зависимости от вашего сценария, см. в разделе «Скорость — Material Design».

Анимируйте пользовательские типы данных путем преобразования в 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 , по сути, представляет собой набор из четырёх значений: красного, зелёного, синего и альфа-канала. Поэтому Color преобразуется в объект AnimationVector4D , содержащий четыре значения с плавающей точкой. Таким образом, каждый тип данных, используемый в анимации, преобразуется в 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 %}