Из этой статьи вы узнаете, как создать 3D-анимацию атомарного загрузчика (atomic loader) в Jetpack Compose.

Источник вдохновения
Эта анимация загрузчика вдохновлена оригинальной работой, выполненной с использованием HTML и CSS Мартином ван Дриелем и имеющей лицензию от Массачусетского технологического института.
Я воссоздал этот эффект с помощью Jetpack Compose, чтобы перенести его на Android.
Создание вращающегося круга
Для начала нужно создать composable-функцию RotatingCircle
. Эта функция рендерит один круг, который будет использоваться для создания загрузчика.
@Composable
fun RotatingCircle(
modifier: Modifier,
rotationX: Float,
rotationY: Float,
rotationZ: Float,
borderColor: Color,
borderWidth: Dp
) {
// Дальнейшая реализация
}
Рисование круга
Чтобы добиться нужного эффекта, вычленяем из этого круга другой и рисуем результат (часть в виде полумесяца) на Canvas
:
Canvas(modifier) {
// Определение пути для главного круга
val mainCircle = Path().apply {
addOval(Rect(size.center, size.minDimension / 2))
}
// Корректировка позиции отделяемого круга слева от borderWidth
val clipCenter = Offset(size.width / 2f - borderWidth.toPx(), size.height / 2f)
// Определение пути для отделяемого круга
val clipCircle = Path().apply {
addOval(Rect(clipCenter, size.minDimension / 2))
}
// Вычленение отделяемого круга из главного круга
val path = Path().apply {
op(mainCircle, clipCircle, PathOperation.Difference)
}
// Рисование отделяемого пути
drawPath(path, borderColor)
}

Трансформация
Теперь используем graphicsLayer
для поворота Canvas
в трехмерном пространстве:
Canvas(
modifier.graphicsLayer {
this.rotationX = rotationX
this.rotationY = rotationY
this.rotationZ = rotationZ
// Для создания эффекта глубины настройте cameraDistance
cameraDistance = 12f * density
}
) {
// Логика рисования
}
Создание загрузчика
Для рендеринга загрузчика определяем composable-функцию AtomicLoader
:
@Composable
fun AtomicLoader(
modifier: Modifier,
color: Color = Color.White,
borderWidth: Dp = 3.dp,
cycleDuration: Int = 1000
)
Параметры:
modifier
: модификатор, который будет применен к контейнеру загрузчика;
color
: цвет загрузчика;
borderWidth
: ширина границы загрузчика;
cycleDuration
: продолжительность одного полного цикла вращения в миллисекундах.
Создание анимации вращения
Чтобы анимировать загрузчик, определим бесконечное вращение, которое будет проходить цикл от 0 до 360 градусов:
val infiniteTransition = rememberInfiniteTransition("InfiniteAtomicLoaderTransition")
val rotation by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(cycleDuration, easing = LinearEasing)
),
label = "AtomicLoaderRotation"
)
Размещение кругов
Наконец, разместим круги внутри composable Box
и применим анимацию вращения:
Box(modifier) {
RotatingCircle(
modifier = Modifier.matchParentSize(),
rotationX = 35f,
rotationY = -45f,
rotationZ = -90f + rotation,
borderColor = color,
borderWidth = borderWidth
)
RotatingCircle(
modifier = Modifier.matchParentSize(),
rotationX = 50f,
rotationY = 10f,
rotationZ = rotation,
borderColor = color,
borderWidth = borderWidth
)
RotatingCircle(
modifier = Modifier.matchParentSize(),
rotationX = 35f,
rotationY = 55f,
rotationZ = 90f + rotation,
borderColor = color,
borderWidth = borderWidth
)
}
Анимация успешно создана. Полный код можно найти на GitHub Gist. А пока рассмотрите возможности использования созданной анимации.
Практическое применение
Создадим Box
с радиальным градиентным фоном и поместим загрузчик в центр, чтобы увидеть результат.
Убедитесь, что загрузчик имеет четко определенный размер! В противном случае он может не отобразиться или демонстрировать неожиданное поведение.
Box(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.radialGradient(
listOf(Color(0xFF3C4B57), Color(0xFF1C262B))
)
),
contentAlignment = Alignment.Center
) {
AtomicLoader(
Modifier.size(100.dp)
)
}
Вывод

Читайте также:
- Как создать анимацию кругового вытеснения в Jetpack Compose
- Как создать форму текстового фона в Jetpack Compose
- Jetpack Compose: настройка Retrofit и Ktor с помощью Dagger Hilt для внедрения зависимостей
Читайте нас в Telegram, VK и Дзен
Перевод статьи Kappdev: How to Create an Atomic Loader in Jetpack Compose