How to add Shimmer animation in Android using Jetpack compose?

Last updated Sep 23, 2021

In this Jetpack compose material tutorial we will learn How to add Shimmer animation in Android using Jetpack compose in Android application. 

Shimmer effect is created by Facebook to show an animation while data is being load from network instead of using traditional circular progress bar for loading.

 

Let's get started

Step 1: Create android application in android studio

Step 2: Follow step for setup Jetpack Compose with Android Studio

First of all add colors for shimmer effect

Go to u i-> theme ->  Colots.kt and add given below color

val simmerEffectColors = listOf(
    Color.LightGray.copy(0.5f),
    Color.LightGray.copy(0.1f),
    Color.LightGray.copy(0.5f)

)

 

 

Before creating list item lets add dependency for constraint layout

implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02"

 

 

Create a data class ShimmerItemData which will contain all the info of list item

data class ShimmerItemData(val name: String, val email: String, val mobileNo: String)

 

 

Now create a composable function for list item where animation will show

@Composable
fun ShimmerItem(brush: Brush, item: ShimmerItemData, showLoading: Boolean) {
    ConstraintLayout(
        modifier = Modifier
            .padding(16.dp)
            .fillMaxWidth().border(
                width = 1.2.dp,
                color = Color.LightGray,
                shape = RectangleShape
            )
    ) {
        val (name, email, mobileNo, loader) = createRefs()
        Text(text = item.name, modifier = Modifier
            .padding(horizontal = 16.dp)
            .constrainAs(name) {
                top.linkTo(parent.top, margin = 16.dp)
            })
        Text(text = item.email, modifier = Modifier
            .padding(horizontal = 16.dp)
            .constrainAs(email) {
                top.linkTo(name.bottom, margin = 8.dp)
            })
        Text(text = item.mobileNo, modifier = Modifier
            .padding(16.dp)
            .constrainAs(mobileNo) {
                top.linkTo(email.bottom)
            })
        if (showLoading) {
            Surface(modifier = Modifier
                .constrainAs(loader) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                    end.linkTo(parent.end)
                    bottom.linkTo(parent.bottom)
                    height = Dimension.fillToConstraints
                    width = Dimension.fillToConstraints
                }, content = {
                Spacer(
                    modifier = Modifier
                        .background(brush)
                        .fillMaxSize()
                )
            })
        }

    }
}

 

 

 

Now create shimmer animation

To creates a linear gradient with the provided colors we are going to use Brush.

@Composable
fun ShimmerAnimation(showLoading: Boolean) {
    val transition = rememberInfiniteTransition()
    val traslateAnimation = transition.animateFloat(
        initialValue = 0f,
        targetValue = 2000f,
        animationSpec = infiniteRepeatable(
            tween(
                durationMillis = 1000,
                easing = FastOutLinearInEasing
            ),
        )
    )

    val brush = Brush.linearGradient(
        colors = simmerEffectColors,
        start = Offset(10f, 10f),
        end = Offset(traslateAnimation.value, traslateAnimation.value)
    )

    ShimmerItem(brush, ShimmerItemData("XYZ", "xyz@gmail.com", "+911234567890"), showLoading)
}

 

 

 

Transitions is used to handle one or more animations.

rememberInfiniteTransition is used when animation is infinite,state based and happens in composition .

Now create a list

@Composable
fun ShimmerAnimationDemo() {
    JetPackTheme {
        val showLoading = remember { mutableStateOf(true) }
        LazyColumn {
            repeat(5) {
                item {
                    ShimmerAnimation(showLoading.value)
                }
            }
        }
        LaunchedEffect(key1 = null, key2 = null) {
            if(showLoading.value){
                delay(2000L)
                showLoading.value = false
            }
        }
    }
}

 

 

Here we have used delay so that you will able to see the effect otherwise you can fetch data from network and after data is fetched successfully then set the value of showLoading to true.

Full code

package com.example.jetpack

import android.os.Bundle
import android.view.WindowManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import com.example.jetpack.ui.theme.JetPackTheme
import com.example.jetpack.ui.theme.simmerEffectColors
import kotlinx.coroutines.delay

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
        setContent {
            ShimmerAnimationDemo()
        }
    }
}

@Composable
fun ShimmerAnimationDemo() {
    JetPackTheme {
        val showLoading = remember { mutableStateOf(true) }
        LazyColumn {
            repeat(5) {
                item {
                    ShimmerAnimation(showLoading.value)
                }
            }
        }
        LaunchedEffect(key1 = null, key2 = null) {
            if(showLoading.value){
                delay(2000L)
                showLoading.value = false
            }
        }
    }
}

@Composable
fun ShimmerAnimation(showLoading: Boolean) {
    val transition = rememberInfiniteTransition()
    val traslateAnimation = transition.animateFloat(
        initialValue = 0f,
        targetValue = 2000f,
        animationSpec = infiniteRepeatable(
            tween(
                durationMillis = 1000,
                easing = FastOutLinearInEasing
            ),
        )
    )

    val brush = Brush.linearGradient(
        colors = simmerEffectColors,
        start = Offset(10f, 10f),
        end = Offset(traslateAnimation.value, traslateAnimation.value)
    )

    ShimmerItem(brush, ShimmerItemData("XYZ", "xyz@gmail.com", "+911234567890"), showLoading)
}

data class ShimmerItemData(val name: String, val email: String, val mobileNo: String)

@Composable
fun ShimmerItem(brush: Brush, item: ShimmerItemData, showLoading: Boolean) {
    ConstraintLayout(
        modifier = Modifier
            .padding(16.dp)
            .fillMaxWidth().border(
                width = 1.2.dp,
                color = Color.LightGray,
                shape = RectangleShape
            )
    ) {
        val (name, email, mobileNo, loader) = createRefs()
        Text(text = item.name, modifier = Modifier
            .padding(horizontal = 16.dp)
            .constrainAs(name) {
                top.linkTo(parent.top, margin = 16.dp)
            })
        Text(text = item.email, modifier = Modifier
            .padding(horizontal = 16.dp)
            .constrainAs(email) {
                top.linkTo(name.bottom, margin = 8.dp)
            })
        Text(text = item.mobileNo, modifier = Modifier
            .padding(16.dp)
            .constrainAs(mobileNo) {
                top.linkTo(email.bottom)
            })
        if (showLoading) {
            Surface(modifier = Modifier
                .constrainAs(loader) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                    end.linkTo(parent.end)
                    bottom.linkTo(parent.bottom)
                    height = Dimension.fillToConstraints
                    width = Dimension.fillToConstraints
                }, content = {
                Spacer(
                    modifier = Modifier
                        .background(brush)
                        .fillMaxSize()
                )
            })
        }

    }
}


@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    ShimmerAnimationDemo()
}

 

 

 

 

Jetpack Shimmer effect to Listview
Recyclerview Shimmer effect with Jetpack Compose example

Article Contributed By :
https://www.rrtutors.com/site_assets/profile/assets/img/avataaars.svg

1470 Views