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 π
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 β¨
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 π