How to create Shimmer Loading Animation with Jetpack Compose

How to create Shimmer Loading Animation with Jetpack Compose

Bored of the circular progress loader? In this tutorial, let us learn how to implement the shimmer loading effect, which looks much better and can significantly improve the UX, when loading a bunch of items. All modern apps like YouTube, Netflix, Facebook use this effect.

Usage: Especially used when loading a list of items.

First create a ShimmerListItem() composable.

@Composable
fun ShimmerListItem(
    isLoading: Boolean,
    barCount: Int,
    modifier: Modifier = Modifier,
    contentAfterLoading: @Composable () -> Unit,
) {
    if (isLoading) {
        Row(modifier = modifier) {
            Column {
                for (i in 1..barCount) {
                    Box(
                        modifier = Modifier
                            .fillMaxWidth((1f / i))
                            .height(20.dp)
                            .clip(RoundedCornerShape(6.dp))
                            .shimmerEffect()
                    )
                    Spacer(modifier = Modifier.height(12.dp))
                }
            }
        }
    } else {
        contentAfterLoading()
    }
}

fun Modifier.shimmerEffect(): Modifier = composed {

    val transition = rememberInfiniteTransition()
    val offsetX by transition.animateFloat(
        initialValue = 0f,
        targetValue = 2000f,
        animationSpec = infiniteRepeatable(
            animation = tween(durationMillis = 1200, easing = FastOutSlowInEasing)
        )
    )
    background(
        brush = Brush.horizontalGradient(
            colors = listOf(
                Color.LightGray.copy(alpha = 0.8f),
                Color.LightGray.copy(alpha = 0.6f),
                Color.LightGray.copy(alpha = 0.8f)
            ),
            startX = 0f,
            endX = offsetX
        )
    )
}

Let's understand the parameters.

  1. isLoading - Boolean which represents the state of the item. It will show the Shimmer effect when true, and the contentAfterLoading composable when false.

  2. barCount - Represents the number of horizontal simmer effect bars in one ShimmerListItem.

  3. modifier - Modifier to edit the size.

  4. contentAfterLoading - Place the item to display after loading is over in here as a composable.

Now simply use it in for example in a LazyColumn() like:

LazyColumn {
    items(itemCount) {
        ShimmerListItem(isLoading = it.isLoading, barCount = 3) {
            Row {...}
        }
    }
}

Preview (with 3 bars):

If you don't want this horizontal bar like shape, or if you want to have the simmer effect anywhere else, you can use it on any other composable (e.g. in a Box) using the Modifier.shimmerEffect() as a modifier. Enjoy!

Thanks for reading this article! Hope you liked it!