Create Gemini loading animation using Jetpack compose

Mind Motion 🧑🏼🎨
Setting meaningful animations is crucial to creating smooth mobile experiences. I’m particularly fond of the term “mind motion,” which means that animation must be logical and predictable by the human mind. Creating a natural and interactive change by morphing the app icon into the app frame is a better alternative to having the user click on the icon to open the app out of nowhere.
When I came across the loading animation for Gemini on mobile, I was quite impressed and decided to try to recreate it. I would appreciate any suggestions in the comments to make it better. 🕺
Breakdown ䷪
Let’s break down the animation and try to replicate it.
- As you may have noticed, the core style of the animation is a gradient.
- The gradient animates across the X-axis. First, it enters from behind the screen, then goes through the screen’s full width, exits out of the screen bounds, and then repeats.
- To make it easier to imagine how the animation goes, Here is a diagram that I crafted to wrap my head around the concept. 😉

💡 Note: It’s essential to start and end the animation outside the screen boundaries to achieve a natural feel.
Implementation 🧑🏻💻
Let’s write code 🙌
We can use Jetpack Compose’s LinearGradient Brush as a skeleton for our animation.
@Stable
fun linearGradient(
colors: List<Color>,
start: Offset = Offset.Zero,
end: Offset = Offset.Infinite,
tileMode: TileMode = TileMode.Clamp
): Brush = LinearGradient(
colors = colors,
stops = null,
start = start,
end = end,
tileMode = tileMode
)- This Composable function draws a gradient in our scene and enables X-axis animation via
startOffsetandendOffset. - I chose to create our animation effect as a
Modifier, To ensure that we can apply it to any Composable. - To begin with, we need to draw the gradient and then animate it.
fun Modifier.animatedGradient(
primaryColor: Color,
containerColor: Color
): Modifier = composed {
val colors = listOf(
primaryColor,
containerColor,
primaryColor
)
background(
brush = Brush.linearGradient(
colors = colors
),
shape = RoundedCornerShape(24.dp)
)
}primaryColoris the main color in the gradient animation.containerColoris the secondary color, It will serve as a backdrop for our animation.- Because
animatedGradientis an extensionModifierwe can access all the operators inside, we will use thebackgroundoperator and bind theBrush.linearGradientas it’s painted. - Lastly, we will assign
RoundedCornerShapeto ourbackground; feel free to adjust the value of the radius, Similar to the Gemini animation I made it24.dp
⚠️ Note: primaryColor and containerColorshould differ from your screen’s background — Anything that can make a good contrast.










