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

Многие 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"
)

Плавная анимация между ключевыми кадрами с помощью 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
    }
)

Ключевые кадры на основе сплайнов особенно полезны для двухмерного перемещения элементов на экране.

В следующих видеороликах показаны различия между 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 (конец), указывающее текущую точку анимации.

На самом деле замедление — это функция, которая принимает дробное значение от 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 :

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