
This is a Jetpack Compose loading animation. It consists of 3 circles. Their sizes and opacity values get animated with the help of coroutine animations. You can download the source code for free below.
The animation is made with Box and Animatable APIs. It uses infiniteRepeatable animation spec so that the animation lasts forever. I set the animation duration to 1500 milliseconds. You can adjust it to accroding to your requirements. I’m animating 3 circles. If you want more or less, you should divide the animation duration by the number of circles and pass the value to the coroutine delay method.
The Jetpack Compose loading animation composable requires two arguments – circleColor and animationDelay. I set some default values. You can change them as per your interest. The circleColor is applied to all the 3 animating circles. The animationDealy is the duration of the animation of each circle. The box size is set to 200.dp.
The animation is applied to both the size and opacity values of the boxes. As the box size increases, the opacity value decreases. It looks like ripple effect. The animation will run forever. Thanks to infiniteRepeatable API for providing RepeatMode.Restart.
If you want to use this composable, you should download the latest version of Android Studio. Jetpack Compose doesn’t work in the older versions.
Related:
Final output:
If the video isn’t working, watch it on the YouTube.
Helpful links to understand the code:
Here are the Gradle files used in the project.
Here is the source code:
MainActivity.kt:
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
/*
You can use the following code for commercial purposes with some restrictions.
Read the full license here: http://semicolonspace.com/semicolonspace-license/
For more designs with source code, visit:
https://semicolonspace.com/jetpack-compose-samples/
*/
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
YourProjectNameTheme(darkTheme = false) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
LoadingAnimation2()
}
}
}
}
}
@Composable
fun LoadingAnimation2(
circleColor: Color = Color.Magenta,
animationDelay: Int = 1500
) {
// 3 circles
val circles = listOf(
remember {
Animatable(initialValue = 0f)
},
remember {
Animatable(initialValue = 0f)
},
remember {
Animatable(initialValue = 0f)
}
)
circles.forEachIndexed { index, animatable ->
LaunchedEffect(Unit) {
// Use coroutine delay to sync animations
// divide the animation delay by number of circles
delay(timeMillis = (animationDelay / 3L) * (index + 1))
animatable.animateTo(
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = animationDelay,
easing = LinearEasing
),
repeatMode = RepeatMode.Restart
)
)
}
}
// outer circle
Box(
modifier = Modifier
.size(size = 200.dp)
.background(color = Color.Transparent)
) {
// animating circles
circles.forEachIndexed { index, animatable ->
Box(
modifier = Modifier
.scale(scale = animatable.value)
.size(size = 200.dp)
.clip(shape = CircleShape)
.background(
color = circleColor
.copy(alpha = (1 - animatable.value))
)
) {
}
}
}
}