How to Create a Spinning Circles Loader in Jetpack Compose

Kappdev
3 min readAug 10, 2024

--

Welcome πŸ™‹

In this article, we’ll create a custom loading animation with circles spinning around a central point in Jetpack Compose.

Let’s dive in πŸš€

Created by Kappdev

Defining the Function

Let’s start by defining the function:

@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)
)

Parameters:

πŸ”΄ modifier πŸ‘‰ A Modifier to be applied to the Canvas hosting the animation.

🟒 centerColor πŸ‘‰ The color of the central static point.

πŸ”΅ circleColors πŸ‘‰ A list of colors for the rotating circles. Each color in the list corresponds to a circle in the loader.

🟠 spec πŸ‘‰ The animation specification for the rotation cycle.

Implementation

Draw Rotating Circle

Let’s abstract the logic for drawing the rotating circle into a separate function:

fun DrawScope.drawRotatingCircle(
degree: Float,
radius: Float,
centerPadding: Float,
strokeWidth: Float,
color: Color
) {
// Convert degree to radians for calculations
val radians = Math.toRadians(degree.toDouble()).toFloat()

// Adjust radius for padding and stroke width
val circleCenterRadius = radius - centerPadding - strokeWidth / 2

// Calculate X coordinate of the circle
val circleX = center.x + circleCenterRadius * cos(radians)

// Calculate Y coordinate of the circle
val circleY = center.y + circleCenterRadius * sin(radians)

// Draw the rotating circle
drawCircle(
color = color,
radius = radius,
center = Offset(circleX, circleY),
style = Stroke(strokeWidth)
)
}

Animating the Angle

To make the circles move, we need to create an infinite animation that runs from 0 to 360 degrees and repeats:

val transition = rememberInfiniteTransition(label = "RotationTransition")
val degree by transition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(spec),
label = "RotationDegree"
)

Drawing

Finally, we can use the Canvas composable to draw the animation:

Canvas(modifier) {
// Define the radius for the central circle
val pointRadius = size.minDimension * 0.1f

// Define the radius for the rotating circles
val circleRadius = size.minDimension / 4

// Define the stroke width for the rotating circles
val strokeWidth = size.minDimension * 0.03f

// Draw the central static circle
drawCircle(
color = centerColor,
radius = pointRadius
)

// Check if there are any rotating circles to draw
if (circleColors.isNotEmpty()) {
// Calculate the angular step between each rotating circle
val degreeStep = 360f / circleColors.size

// Draw each rotating circle with its color
for (circle in circleColors.indices) {
val baseAngle = degreeStep * circle
drawRotatingCircle(baseAngle + degree, circleRadius, pointRadius, strokeWidth, circleColors[circle])
}
}
}

Congratulations πŸ₯³! We’ve successfully built it πŸ‘. You can find the full code on GitHub Gist πŸ§‘β€πŸ’». Let’s explore the usage πŸ‘‡

Practical Usage πŸ’β€β™‚οΈ

Using the SpinningCirclesLoader function is straightforward. Let's explore a few variants:

// One Circle
SpinningCirclesLoader(
modifier = Modifier.size(100.dp),
circleColors = listOf(Color.Red)
)

// Two Circles
SpinningCirclesLoader(
modifier = Modifier.size(100.dp),
circleColors = listOf(Color.Yellow, Color.Blue)
)

// Three Circles (Default)
SpinningCirclesLoader(Modifier.size(100.dp))

// Four Circles
SpinningCirclesLoader(
modifier = Modifier.size(100.dp),
circleColors = listOf(Color.Red, Color.Green, Color.Blue, Color.Yellow)
)

// Custom Easing
SpinningCirclesLoader(
modifier = Modifier.size(100.dp),
spec = tween(800, easing = FastOutLinearInEasing)
)

Output ✨

Custom Loaders | Jetpack Compose

7 stories

Thank you for reading this article! ❀️ If you found it enjoyable and valuable, show your appreciation by clapping πŸ‘ and following Kappdev for more exciting articles 😊

--

--

Kappdev

πŸ’‘ Curious Explorer 🧭 Kotlin and Compose enthusiast πŸ‘¨β€πŸ’» Passionate about self-development and growth ❀️‍πŸ”₯ Push your boundaries πŸš€