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()
}
|
 |
 |