Из этой статьи вы узнаете, как в Jetpack Compose создать пользовательскую анимацию загрузки с кругами, вращающимися вокруг центральной точки.

Определение функции
Начнем с определения функции:
@Composable
fun SpinningCirclesLoader(
modifier: Modifier,
centerColor: Color = Color.Black,
circleColors: List<Color> = listOf(Color.Red, Color.Green, Color.Blue),
spec: DurationBasedAnimationSpec<Float> = tween(800, easing = LinearEasing)
)
Параметры
-
modifier
: модификатор, применяемый к холсту (canvas), на котором происходит анимация;
-
centerColor
: цвет центральной статической точки;
-
circleColors
: список цветов для вращающихся кругов (каждый цвет в списке соответствует кругу в загрузчике);
-
spec
: спецификация анимации для цикла вращения.
Реализация
1. Определение логики вращающегося круга
Абстрагируем логику рисования вращающегося круга в отдельную функцию:
fun DrawScope.drawRotatingCircle(
degree: Float,
radius: Float,
centerPadding: Float,
strokeWidth: Float,
color: Color
) {
// Преобразование градусов в радианы для вычислений
val radians = Math.toRadians(degree.toDouble()).toFloat()
// Настройка радиуса для отступа и ширины штриха
val circleCenterRadius = radius - centerPadding - strokeWidth / 2
// Вычисление координаты X круга
val circleX = center.x + circleCenterRadius * cos(radians)
// Вычисление координаты Y круга
val circleY = center.y + circleCenterRadius * sin(radians)
// Отрисовка вращающегося круга
drawCircle(
color = color,
radius = radius,
center = Offset(circleX, circleY),
style = Stroke(strokeWidth)
)
}
2. Определение угла вращения
Чтобы заставить круги двигаться, создадим бесконечную анимацию, которая проходит от 0 до 360 градусов и повторяется:
val transition = rememberInfiniteTransition(label = "RotationTransition")
val degree by transition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(spec),
label = "RotationDegree"
)
3. Выполнение анимации с вращающимися кругами
Наконец, можем использовать Composable-функцию Canvas
для выполнения анимации:
Canvas(modifier) {
// Определение радиуса центрального круга
val pointRadius = size.minDimension * 0.1f
// Определение радиуса вращающихся кругов
val circleRadius = size.minDimension / 4
// Определение ширины штриха для вращающихся кругов
val strokeWidth = size.minDimension * 0.03f
// Отрисовка центрального статического круга
drawCircle(
color = centerColor,
radius = pointRadius
)
// Проверка наличия вращающихся кругов для отрисовки
if (circleColors.isNotEmpty()) {
// Вычисление углового шага между каждым вращающимся кругом
val degreeStep = 360f / circleColors.size
// Отрисовка каждого вращающегося круга своим цветом
for (circle in circleColors.indices) {
val baseAngle = degreeStep * circle
drawRotatingCircle(baseAngle + degree, circleRadius, pointRadius, strokeWidth, circleColors[circle])
}
}
}
Анимация успешно создана. Полный код можно найти на GitHub Gist. А теперь изучим возможности использования.
Практическое применение
Функция SpinningCirclesLoader
довольно проста в применении. Рассмотрим несколько вариантов использования:
// Один круг
SpinningCirclesLoader(
modifier = Modifier.size(100.dp),
circleColors = listOf(Color.Red)
)
// Два круга
SpinningCirclesLoader(
modifier = Modifier.size(100.dp),
circleColors = listOf(Color.Yellow, Color.Blue)
)
// Три круга (по умолчанию)
SpinningCirclesLoader(Modifier.size(100.dp))
// Четыре круга
SpinningCirclesLoader(
modifier = Modifier.size(100.dp),
circleColors = listOf(Color.Red, Color.Green, Color.Blue, Color.Yellow)
)
// Пользовательское упрощение
SpinningCirclesLoader(
modifier = Modifier.size(100.dp),
spec = tween(800, easing = FastOutLinearInEasing)
Вывод:

Читайте также:
- Адаптируем Android-приложение к большим размерам экрана с помощью классов window-size
- Новые способы оптимизации стабильности в Jetpack Compose
- Что нового в Jetpack
Читайте нас в Telegram, VK и Дзен
Перевод статьи Kappdev: How to Create a Spinning Circles Loader in Jetpack Compose