Источник вдохновения
В статье на сайте Android Developer говорится, что в Android Studio Koala теперь можно просматривать анимации Jetpack Compose. И я решил попробовать.
Создание нового проекта
В Android Studio Koala создайте новый проект и выберите «Empty Activity».

Проект, созданный по умолчанию, использует зависимости toml.
Как видно ниже, он использует версию composeBom «2024.04.01», которая включает версию compose-анимации 1.6.6.

Если не используете toml, также можете добавить Compose-зависимости следующим образом:
def compose_bom = platform('androidx.compose:compose-bom:2024.04.01')
implementation compose_bom
androidTestImplementation compose_bom
Какую анимацию реализовать?
Я хочу добиться следующего эффекта: анимация обратной связи, показанная в Beacon Jumpstart Guide здесь.
Мне кажется, эта анимация с кивками и покачиванием головой выглядит интересно.

Подготовка файлов ресурсов SVG
ic_yes.xml:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#D79400"
android:pathData="M5.538 14.026A19.392 19.392 0 0 1 12 12.923c2.26 0 4.432.388 6.462 1.103-1.087 2.61-3.571 4.436-6.462 4.436-2.891 0-5.375-1.825-6.462-4.436zm1.847-3.872a1.846 1.846 0 1 1 0-3.692 1.846 1.846 0 0 1 0 3.692zm9.23 0a1.846 1.846 0 1 1 0-3.692 1.846 1.846 0 0 1 0 3.692z"></path>
</vector>

ic_no.xml:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#D79400"
android:pathData="M7.385 13.846a1.846 1.846 0 1 1 0-3.692 1.846 1.846 0 0 1 0 3.692zm9.23 0a1.846 1.846 0 1 1 0-3.692 1.846 1.846 0 0 1 0 3.692zm-.967 4.95a.992.992 0 0 1-.615-.212c-1.701-1.349-4.364-1.349-6.065 0a.998.998 0 0 1-1.36-.123.895.895 0 0 1 .127-1.3A6.897 6.897 0 0 1 12 15.692c1.555 0 3.069.521 4.266 1.467.41.326.467.909.127 1.3a.982.982 0 0 1-.745.335z"></path>
</vector>

Что такое анимация по ключевым кадрам?
Что же такое ключевой кадр? Анимация по ключевым кадрам позволяет разработчикам задавать несколько временных точек (ключевых кадров) и соответствующие им значения в процессе анимации. Для каждого из этих ключевых кадров можно задать различные кривые интерполяции.
Вот пример из официальной документации:
val value by animateFloatAsState(
targetValue = 1f,
animationSpec = keyframes {
durationMillis = 375 //длительность - 375 мс
0.0f at 0 with LinearOutSlowInEasing // для 0-15 мс
0.2f at 15 with FastOutLinearInEasing // для 15-75 мс
0.4f at 75 // мс
0.4f at 225 // мс
}
)
Замедлим время и понаблюдаем
Замедлим скорость воспроизведения и внимательно понаблюдаем за анимацией с кивками и покачиванием головой, которую мы хотим реализовать:

Нетрудно заметить, что лицо человечка перемещается только по осям y и x. Глаза и рот остаются единым целым. Более того, смещение больше в начале и меньше в конце, а начальное и конечное смещения равны 0.
Это значительно упрощает задачу. Мне нужно только определить смещения для кивания и покачивания головой.
После покадрового анализа я обнаружил, что при анимации кивания лицо человечка попеременно поднимается и опускается 4 раза с большим смещением, затем движется вверх и вниз по одному разу с меньшим смещением. Начальное и конечное смещения равны 0.
Анимация качания головой происходит по той же схеме: лицо человечка поворачивается влево и вправо 4 раза с большим смещением, затем движется влево и вправо по одному разу с меньшим смещением. Начальное и конечное смещения равны 0.
Перейдем к коду
Это позволило создать окончательный вариант кода анимации:
val animationDuration = 1500 // Общая продолжительность анимации в мс.
// Определение ключевых точек в процентах прогресса времени для анимации, от 0 (начало) до 1 (конец).
val keyFrames = listOf(
0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f
)
//Здесь задаются значения смещения для каждого ключевого кадра.
//Коэффициент умножения позволяет легко масштабировать интенсивность анимации.
val multiply = 1.6f
val offsets = listOf(
0f,
-3.5f * multiply,
3.5f * multiply,
-3.5f * multiply,
3.5f * multiply,
-3.5f * multiply,
3.5f * multiply,
-3.5f * multiply,
2.6f * multiply,
-2.6f * multiply,
0f
)
//Создание анимированного плавающего значения для вертикального перемещения.
//Запускается, когда isYesAnimating становится true.
val offsetY by animateFloatAsState(targetValue = if (isYesAnimating) 0.01f else 0f,
animationSpec = keyframes {
durationMillis = animationDuration
//Каждый ключевой кадр сопоставляется с соответствующим смещением.
keyFrames.zip(offsets).forEach { (time, offset) ->
//Время для каждого ключевого кадра рассчитывается как доля от общей продолжительности.
offset at (time * animationDuration).toInt() using LinearEasing
}
})
//Создание анимированного плавающего значения для горизонтального перемещения.
//Запускается, когда isNopeAnimating становится true.
val offsetX by animateFloatAsState(targetValue = if (isNopeAnimating) 0.01f else 0f,
animationSpec = keyframes {
durationMillis = animationDuration
//Каждый ключевой кадр сопоставляется с соответствующим смещением.
keyFrames.zip(offsets).forEach { (time, offset) ->
//Время для каждого ключевого кадра рассчитывается как доля от общей продолжительности.
offset at (time * animationDuration).toInt() using LinearEasing
}
})
Я настроил использование ключевых кадров. Заменил ‘offset at time’ на ‘offset at percent’.
Таким образом, при изменении продолжительности мне нужно только изменить animationDuration, и никаких других изменений в коде не требуется.
Предварительный просмотр анимации в Android Studio
В Android Studio вы можете просмотреть эту анимацию по ключевым кадрам, нажав на «Start Animation Preview».

Видно, что Android Studio предоставляет довольно продвинутые средства управления анимацией, такие как:
- Временная шкала анимации. Внизу находится временная шкала, показывающая продолжительность и ход анимации.
- Элементы управления анимацией. Для предварительного просмотра анимации можно использовать кнопки воспроизведения, паузы, перемотки и регулировки скорости.

Предварительный просмотр анимации
Вот предварительный просмотр анимации кивания и покачивания головой:

Весь проект находится здесь.
Читайте также:
- Отладка зависимостей в Gradle
- Компонентный подход: реализация экранов с помощью библиотеки Decompose. Часть 2
- Как создать анимацию кругового вытеснения в Jetpack Compose
Читайте нас в Telegram, VK и Дзен
Перевод статьи zty5678: How to Preview Jetpack Compose keyFrame Animation in Android Studio





