Animation In Compose Series (Part 1) — Animated Visiblity and Animated Content
Hi Devs, I am presenting you my first series of Articles — ANIMATIONS MADE EASY for you.
Animations are an important aspect of a smooth and feel-good App. Animations in Compose have been made very much easier and simpler. So I have bought you the Go-To Guide for Animations in Compose.
Let's start with the basic once First -
Animated Visibility
This is your view.visibility = View.VISIBLE and view.visibility = View.INVISIBLE of Compose.
Simply put, we can make any Composable visible and invisible with this.
Here is how you can use it in the most simple way
Box(modifier = Modifier.fillMaxSize()) {
var isItemVisible by remember {
mutableStateOf(false)
}
Column(modifier = Modifier.fillMaxWidth()) {
AnimatedVisibility(visible = isItemVisible, modifier = Modifier.size(200.dp)) {
Image(
painter = painterResource(id = R.drawable.kodee),
contentDescription = "Kodee"
)
}
}
Button(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 20.dp),
onClick = { isItemVisible = !isItemVisible }) {
Text(text = "Hide/Unhide")
}
}
Here as you can see isItemVisible is the state used to hide/unhide the Image
Now let’s change the animation here.
AnimatedVisibility(
visibleState = state,
modifier = Modifier.size(200.dp),
enter = fadeIn(),
exit = fadeOut()
) {
Image(
painter = painterResource(id = R.drawable.kodee),
contentDescription = "Kodee"
)
}
Here as you can see we have changed the default animation which is slideIn/slideOut to fadeIn / fadeOut
Now let’s try to change the duration of the animation here.
AnimatedVisibility(
visibleState = state,
modifier = Modifier.size(200.dp),
enter = fadeIn(animationSpec = tween(3000)),
exit = fadeOut(animationSpec = tween(3000))
) {
Image(
painter = painterResource(id = R.drawable.kodee),
contentDescription = "Kodee"
)
}
Here as you can see we added an Animation duration of 3000ms.
You can do many more things play around with different Enter and Exit animations such as slideIn/slideOut, scaleIn/scaleOut, expandIn/shrinkOut, and much more, and change things accordingly.
Now let's see how to listen to the state of Animation in AnimatedVisibility. AnimatedVisiblity gives us a variant that takes a MutableTransitionState. It is useful for observing the animation state. Let’s see how
Box(modifier = Modifier.fillMaxSize()) {
val state = remember {
MutableTransitionState(initialState = false).apply {
targetState = true
}
}
Column(modifier = Modifier.fillMaxWidth()) {
AnimatedVisibility(
visibleState = state,
modifier = Modifier.size(200.dp),
enter = fadeIn(animationSpec = tween(2000)),
exit = fadeOut(animationSpec = tween(2000))
) {
Image(
painter = painterResource(id = R.drawable.kodee),
contentDescription = "Kodee"
)
}
}
Column(
modifier = Modifier.align(Alignment.BottomCenter),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = Color.White,
fontSize = 18.sp,
text = when {
state.isIdle && state.currentState -> "Visible"
!state.isIdle && state.currentState -> "Disappearing"
state.isIdle && !state.currentState -> "Invisible"
else -> "Appearing"
}
)
Button(
modifier = Modifier
.padding(bottom = 20.dp),
onClick = { state.targetState = !state.currentState }) {
Text(text = "Hide/Unhide")
}
}
}
As we can see here we can pass a MutableTransitionState listen to the change in States and use them.
I have added a 2-second duration to see the change in States.
Now let’s see how would I animate only once which is a popular question from many devs. Using the above MutableTransitionState you could do that easily.
Box(modifier = Modifier.fillMaxSize()) {
val state = remember {
MutableTransitionState(initialState = false).apply {
targetState = true
}
}
Column(modifier = Modifier.fillMaxWidth()) {
AnimatedVisibility(
visibleState = state,
modifier = Modifier.size(200.dp),
enter = fadeIn(animationSpec = tween(2000)),
exit = fadeOut(animationSpec = tween(2000))
) {
Image(
painter = painterResource(id = R.drawable.kodee),
contentDescription = "Kodee"
)
}
}
}
Just keep the target state as true and don't change the state. That's it. Simple
Done with AnimatedVisiblity let's move on to another.
Animated Content
This is another composable which animates its content as it changes based on a target state.
This Composable is good for —
- Animating Something when some state changes.
- It can also work as an AnimatedVisiblity composable
Let’s see a basic usage with it first.
Column(modifier = Modifier.fillMaxSize()) {
var counter by remember {
mutableStateOf(1)
}
AnimatedContent(targetState = counter, label = "Fading counter Animation") {
Text(
text = it.toString(),
fontWeight = FontWeight.Bold,
modifier = Modifier
.fillMaxWidth()
.padding(20.dp),
fontSize = 30.sp
)
}
Button(onClick = { counter++ }) {
Text(text = "Increase Count")
}
}
Here as you can see as soon as the state of the counter changes or the counter value changes the animation is restarted again.
This is best suited for Counter value animations or changes of images and much more.
Let’s see how you can add animations like we added in AnimatedVisiblity
Column(modifier = Modifier.fillMaxSize()) {
var counter by remember {
mutableIntStateOf(1)
}
AnimatedContent(
targetState = counter,
label = "Fading counter Animation",
transitionSpec = {
fadeIn(tween(2000)) togetherWith fadeOut(tween(2000))
}
) {
Text(
text = it.toString(),
fontWeight = FontWeight.Bold,
modifier = Modifier
.fillMaxWidth()
.padding(20.dp),
fontSize = 30.sp
)
}
Button(onClick = { counter++ }) {
Text(text = "Increase Count")
}
}
Here as you can see we added the animation inside the transitionSpec lambda.
We have an infix function named togetherwith() to combine Enter and Exit animation.
You can add many more animations and play around with other animations too.
Here is the GitHub repo with samples of Animation — https://github.com/PalankiBharat/Compose-Animation-Samples.git
I am back and will continue writing more and continue this series with more interesting and exciting Animations.
Follow me and Stay tuned for more such content. Feedback would be appreciated as always.
A clap also would be appreciated but a read would be enough.
Thank You and have a Happy coding Journey. :)
You can connect with me at LinkedIn — Bharat Kumar