Creating a Loading Button in Jetpack Compose

Creating the loading indicator dots

Creating the bouncing loading composable

The row of dots

Animating the dots

  1. As we want our dots to be staggered, we define an animation delay that determines how much delayed a dot animation is relative to the previous dot animation. Because we want the dots to animation in a harmonious way, we ensure that the delays between dots are all the same; we do that by dividing the animation duration by the number of dots.
  2. We define a remembered variable that holds the animation value that we will use to animate the dots.
  3. We use a LaunchedEffect to trigger the start of the animation. Because the key is Unit, this will start when the composable enters the composition and won’t be cancelled until the composable leaves the composition.
  4. Next we define the animation, with the start value being half the dot height (so that it initially starts at its downmost position), and the target as minus half the dot height, so that the end position is the topmost one. For our animation we use a tweeen that will linearly interpolate between the 2 values, and because we want the animation to revert and start over again, we specify a repeatMode of RepeatMode.Reverse.
  5. We delay each dot by the delay we calculated above, and we multiply it by the dot index (we will see where this comes from in a minute).
  6. Finally, we specify the animation callback that will simply udpate our remembered variable with the animation value.
  1. Using the animation we described earlier, we create a list of those, one for each dot we want to render. This is where the index that we use to offset each animation comes from.
  2. In our Row, we iterate over the animations we just built and for each we add a Dot.
  3. Each of these Dots is offset vertically, by the amount specified by our remembered animation value.

Creating the animating button

  1. We pass an animating boolean that tells us if the dots are animating.
  2. Our animated value is remembered on the animating value, so that if we toggle the animating flag, we reset the dots to their resting position.
  3. The LaaunchedEffect is also using the animating flag as the key, so that when we toggle animating the previous LaunchedEffect will be cancelled (the animation will stop) and a new LaunchedEffect will trigger. Note that, if we are not animating, then we do not call animate and our animatedValue will be simply 0f all the time, so the dots will be at rest.
  1. We define our LoadingButton composable mimicking the Button from Jetpack Compose. I used some of the attributes of Button and left others out, but we coud have copied all the attributes if we may expect to need them. Besides the Button attributes, we have the loading flag and the indicator spacing.
  2. Next we define the 2 alpha animations for the idle and busy contents, they run opposite one another (one runs from 1f to 0f, the other from 0f to 1f).
  3. We are leveraging the Button from Jetpack Compose as our root element.
  4. Inside our Button we have a Box — as described, this will ensure the Button is as wide and tall as needed and doesn’t change size when we toggle between idle and busy content.
  5. We specify a center alignment for the button content, so that both the idle and busy contents are nicely centered.
  6. Next we display the loading indicator we built earlier, passing the loading flag as the animating toggle.
  7. We add a graphicsLayer modifier to animate the alpha of the loading indicator.
  8. We wrap the idle content in a Box
  9. Because we want to control its alpha based on whether we are loading or not.
  10. Finally, we render the content.

Additional animations

  1. We pass our enum to indicate what kind of animation we want.
  2. The remembered animated value is keyd off the animation type, so that if we change it, the value resets back to 0.
  3. Likewise, the LaunchedEffect also keys off the animation type, so that we cancel and restart the animation if the value changes.
  4. We use the extension properties we just defined to get the animation attributes.
  5. Finally, based on the type of animation we want, we either use offset or alpha for the dots, using the then property of Modifier.




Senior Android Developer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How to create Collection with Candy Machine V2 from scratch

Handling Proguard as Library Developer or in a Multi-Module Android Application

How to Push a Docker Image to the AWS ECR

Alexa user Account Linking using AWS Cognito

Unstructured Data Migration “Factory” Powered by StorageX®

Laravel Multi-Tenant App Setup — Part 0

From Swamp to Swarm


Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Francesc Vilarino Guell

Francesc Vilarino Guell

Senior Android Developer

More from Medium

Bottom Navigation Jetpack Compose.

Jetpack Compose Logo

Passing arguments to screens in Jetpack Compose

Bite-size Jetpack Compose: Navigation

ViewPager in Jetpack Compose with dot indicators (within minutes)