Многие 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.
stiffness определяет, насколько быстро пружина должна двигаться к конечному значению. Значение по умолчанию – Spring.StiffnessMedium.
val value by animateFloatAsState( targetValue = 1f, animationSpec = spring( dampingRatio = Spring.DampingRatioHighBouncy, stiffness = Spring.StiffnessMedium ), label = "spring spec" )
spring может обрабатывать прерывания более плавно, чем типы, основанные на длительности, AnimationSpec, поскольку гарантирует непрерывность скорости при изменении целевого значения в середине анимации. spring используется в качестве AnimationSpec по умолчанию во многих Animation API, например animate*AsState и updateTransition.
Например, если мы применим конфигурацию spring к следующей анимации, которая управляется касанием пользователя, то при прерывании анимации по мере ее выполнения вы увидите, что использование tween не реагирует так плавно, как использование spring.
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 анимируется на основе значений снимка, указанных в разных временных метках в течение анимации. В любой момент времени значение анимации будет интерполировано между значениями двух ключевых кадров. Для каждого из этих ключевых кадров можно задать смягчение, чтобы определить кривую интерполяции.
Указывать значения для 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.
FastOutSlowInEasingLinearOutSlowInEasingFastOutLinearEasingLinearEasingCubicBezierEasing- Посмотрите
Анимируйте пользовательские типы данных, преобразуя их в 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:
Color.VectorConverterDp.VectorConverterOffset.VectorConverterInt.VectorConverterFloat.VectorConverterIntSize.VectorConverter
Рекомендуем
- Примечание. Текст ссылки показывается, когда JavaScript отключен.
- Анимация на основе значений
- Итеративная разработка кода {:#iterative-code-dev }
- Анимации в Compose