In this blog, I will show how to implement the shimmer effect in an Android app using Jetpack Compose. This tutorial shares exactly how to get it done quickly shimmer loading effect with Jetpack Compose.
Add the Shimmer Animation Components
Before creating the shimmer effect, you’ll need to set up your Jetpack Compose environment. Make sure you have a project open in Android Studio and that you’ve imported the necessary dependencies needed for Jetpack Compose (e.g., androidx.compose).
Once you done with dependency let create a @Composable function named with ShimmerItem.
@Composable fun ShimmerItem( isLoading: Boolean, actualContent: @Composable () -> Unit, modifier: Modifier = Modifier ) { // If actual content is in loading state , display it shimmer Items if (isLoading) { Row(modifier = modifier) { Box( modifier = Modifier .fillMaxWidth() ) } } else { // If actual content is loaded, display it actualContent() } }
Customize the Shimmer View.
At the above snapshot I just created one box, Now we have to customised it based on view. So below code snippet, I creating a shimmer view as per feature image, You can create as per own actual view.
@Composable fun ShimmerItem( isLoading: Boolean, actualContent: @Composable () -> Unit, modifier: Modifier = Modifier ) { // If actual content is in loading state , display it shimmer Items if (isLoading) { Row(modifier = modifier) { Box( modifier = Modifier .size(80.dp) .clip(CircleShape) .shimmerEffect() ) Spacer(modifier = Modifier.width(16.dp)) Column( modifier = Modifier .weight(1f) .align(CenterVertically) ) { Box( modifier = Modifier .fillMaxWidth() .height(20.dp) .shimmerEffect() ) Spacer(modifier = Modifier.height(16.dp)) Box( modifier = Modifier .fillMaxWidth(0.7f) .height(20.dp) .shimmerEffect() ) } } } else { // If actual content is loaded, display it actualContent() } }
Set the Colors, Angle and Opacity for the Shine in the Shimmer Effect.
It time to add shimmer effect on View that we created. So let create a Kotlin extension like Modifier.shimmerEffect and set the color, animation angle and the opacity of View.
private fun Modifier.shimmerEffect(): Modifier = composed { var size by remember { mutableStateOf(IntSize.Zero) } val transition = rememberInfiniteTransition() val startOffsetX by transition.animateFloat( initialValue = -2 * size.width.toFloat(), targetValue = 2 * size.width.toFloat(), animationSpec = infiniteRepeatable( animation = tween(1000) ) ) background( brush = Brush.linearGradient( colors = listOf( Color(0xFFB9B5B5), Color(0xFF837F7F), Color(0xFFC2C1C1), ), start = Offset(startOffsetX, 0f), end = Offset(startOffsetX + size.width.toFloat(), size.height.toFloat()) ) ).onGloballyPositioned { size = it.size } }
Complete source shimmer loading effect Item View
package com.compose.shimmereffectexample import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.tween 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.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.composed import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp @Composable fun ShimmerItem( isLoading: Boolean, actualContent: @Composable () -> Unit, modifier: Modifier = Modifier ) { // If actual content is in loading state , display it shimmer Items if (isLoading) { Row(modifier = modifier) { Box( modifier = Modifier .size(80.dp) .clip(CircleShape) .shimmerEffect() ) Spacer(modifier = Modifier.width(16.dp)) Column( modifier = Modifier .weight(1f) .align(CenterVertically) ) { Box( modifier = Modifier .fillMaxWidth() .height(20.dp) .shimmerEffect() ) Spacer(modifier = Modifier.height(16.dp)) Box( modifier = Modifier .fillMaxWidth(0.7f) .height(20.dp) .shimmerEffect() ) } } } else { // If actual content is loaded, display it actualContent() } } private fun Modifier.shimmerEffect(): Modifier = composed { var size by remember { mutableStateOf(IntSize.Zero) } val transition = rememberInfiniteTransition() val startOffsetX by transition.animateFloat( initialValue = -2 * size.width.toFloat(), targetValue = 2 * size.width.toFloat(), animationSpec = infiniteRepeatable( animation = tween(1000) ) ) background( brush = Brush.linearGradient( colors = listOf( Color(0xFFB9B5B5), Color(0xFF837F7F), Color(0xFFC2C1C1), ), start = Offset(startOffsetX, 0f), end = Offset(startOffsetX + size.width.toFloat(), size.height.toFloat()) ) ).onGloballyPositioned { size = it.size } }
How to use Shimmer Effect with own View
In this shimmer effect android example, will show shimmer loading effect until actual content is loading. Just like attached video. If you wish to show how to create list follow out this Ultimate Guide to Jetpack Compose List. Let create composable list in actual content and use ShimmerItem on that. just like below
package com.compose.shimmereffectexample import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.Icon import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AccountCircle import androidx.compose.runtime.* import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.compose.shimmereffectexample.ui.theme.ShimmerEffectExampleTheme import kotlinx.coroutines.delay class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ShimmerEffectExampleTheme { var isLoading by remember { mutableStateOf(true) } LaunchedEffect(key1 = true) { delay(2000) isLoading = false } // Call Shimmer effect using Jetpack Compose ShimmerEffectListView(isLoading) } } } } @Composable fun ShimmerEffectListView(isLoading: Boolean) { LazyColumn( modifier = Modifier.fillMaxSize() ) { items(20) { ShimmerItem( isLoading = isLoading, actualContent = { ActualContent() }, modifier = Modifier .fillMaxWidth() .padding(16.dp) ) } } } /** * Actual Listview that you want to display once shimmer goes out */ @Composable fun ActualContent() { Row( modifier = Modifier .fillMaxWidth() .padding(16.dp) ) { Icon( imageVector = Icons.Default.AccountCircle, contentDescription = null, modifier = Modifier.size(80.dp) ) Spacer(modifier = Modifier.width(16.dp)) Text( text = "This is a text to show that our shimmer loading effect " + "is looking good", modifier = Modifier.align(CenterVertically) ) } }
Conclusion
So far what we done in tutorial, We create on ShimmerItem that with color and animation, Same Item view we have used in List. Let run the project, it will run and up, so that way you can create a Shimmer Effect in an Android using Jetpack Compose.
If you have any query please let me know. Follow me on social media for latest articles