Jetpack Compose, Android’s modern UI toolkit, provides powerful and declarative APIs for building UIs. One of the most engaging aspects of modern UIs is the use of animations. Jetpack Compose offers a straightforward way to animate the visibility of composables using the AnimatedVisibility
composable, complete with customizable transitions. This article explores how to use AnimatedVisibility
to create captivating and smooth transitions in your Compose apps.
What is AnimatedVisibility
in Jetpack Compose?
AnimatedVisibility
is a composable provided by Jetpack Compose that allows you to animate the appearance and disappearance of UI elements. It extends beyond simple visibility toggling by enabling transitions that define how the content animates in or out.
Why Use AnimatedVisibility
?
- Improved User Experience: Smooth transitions enhance the perceived performance and polish of your application.
- Engagement: Thoughtful animations capture the user’s attention and guide them through the UI.
- Declarative API: Simple and expressive syntax integrates seamlessly with Jetpack Compose’s declarative nature.
How to Implement Animated Visibility Transitions
Implementing animated visibility in Jetpack Compose involves using the AnimatedVisibility
composable along with transition specifications. Here’s a step-by-step guide:
Step 1: Add Necessary Dependencies
Ensure your project has the required dependencies. Add the following to your build.gradle.kts
file:
dependencies {
implementation("androidx.compose.animation:animation-core:1.6.0") // or newer
implementation("androidx.compose.animation:animation:1.6.0") // or newer
implementation("androidx.compose.ui:ui:1.6.0") // Ensure you are on the latest version
implementation("androidx.compose.material:material:1.6.0") // Add material dependencies
}
Step 2: Basic Usage of AnimatedVisibility
The simplest way to use AnimatedVisibility
is to wrap the composable you want to animate. Here’s an example that fades content in and out:
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun BasicAnimatedVisibility() {
var isVisible by remember { mutableStateOf(true) }
Column {
Button(onClick = { isVisible = !isVisible }) {
Text("Toggle Visibility")
}
AnimatedVisibility(
visible = isVisible,
enter = fadeIn(),
exit = fadeOut()
) {
Text("This text will fade in and out.")
}
}
}
@Preview(showBackground = true)
@Composable
fun PreviewBasicAnimatedVisibility() {
BasicAnimatedVisibility()
}
In this code:
isVisible
is a state variable that tracks the visibility of theText
composable.AnimatedVisibility
wraps theText
composable.enter = fadeIn()
specifies that the composable should fade in when becoming visible.exit = fadeOut()
specifies that the composable should fade out when becoming invisible.
Step 3: Using Different Transition Effects
AnimatedVisibility
provides a variety of built-in transitions. Let’s explore a few common ones.
Slide In/Out
To slide the composable in and out, you can use slideInVertically
and slideOutVertically
:
import androidx.compose.animation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.Alignment
@Composable
fun SlideAnimatedVisibility() {
var isVisible by remember { mutableStateOf(true) }
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = { isVisible = !isVisible }) {
Text("Toggle Visibility")
}
AnimatedVisibility(
visible = isVisible,
enter = slideInVertically(
initialOffsetY = { fullHeight -> -fullHeight }
),
exit = slideOutVertically(
targetOffsetY = { fullHeight -> -fullHeight }
)
) {
Text("This text will slide in and out from the top.")
}
}
}
@Preview(showBackground = true)
@Composable
fun PreviewSlideAnimatedVisibility() {
SlideAnimatedVisibility()
}
Here, initialOffsetY
specifies the initial offset from which the composable slides in, and targetOffsetY
specifies where it slides out to.
Expand/Shrink
You can use expandIn
and shrinkOut
to create an expanding/shrinking effect:
import androidx.compose.animation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun ExpandShrinkAnimatedVisibility() {
var isVisible by remember { mutableStateOf(true) }
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = { isVisible = !isVisible }) {
Text("Toggle Visibility")
}
AnimatedVisibility(
visible = isVisible,
enter = expandIn(expandFrom = Alignment.Center),
exit = shrinkOut(shrinkTowards = Alignment.Center)
) {
Text("This text will expand and shrink.")
}
}
}
@Preview(showBackground = true)
@Composable
fun PreviewExpandShrinkAnimatedVisibility() {
ExpandShrinkAnimatedVisibility()
}
This example uses expandFrom
and shrinkTowards
to specify the origin from which the content expands and shrinks.
Combining Transitions
You can combine multiple transitions to create more complex effects. For example, combine fading and sliding:
import androidx.compose.animation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun CombinedAnimatedVisibility() {
var isVisible by remember { mutableStateOf(true) }
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = { isVisible = !isVisible }) {
Text("Toggle Visibility")
}
AnimatedVisibility(
visible = isVisible,
enter = fadeIn() + slideInVertically(),
exit = fadeOut() + slideOutVertically()
) {
Text("This text will fade and slide.")
}
}
}
@Preview(showBackground = true)
@Composable
fun PreviewCombinedAnimatedVisibility() {
CombinedAnimatedVisibility()
}
Step 4: Customizing Transition Duration and Easing
You can customize the duration and easing of transitions using animationSpec
. Here’s an example that customizes the fade-in effect:
import androidx.compose.animation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.animation.core.tween
@Composable
fun CustomDurationAnimatedVisibility() {
var isVisible by remember { mutableStateOf(true) }
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = { isVisible = !isVisible }) {
Text("Toggle Visibility")
}
AnimatedVisibility(
visible = isVisible,
enter = fadeIn(animationSpec = tween(durationMillis = 1000)),
exit = fadeOut(animationSpec = tween(durationMillis = 500))
) {
Text("This text will fade in and out with custom durations.")
}
}
}
@Preview(showBackground = true)
@Composable
fun PreviewCustomDurationAnimatedVisibility() {
CustomDurationAnimatedVisibility()
}
In this code, tween(durationMillis = 1000)
specifies a 1000ms duration for the fade-in effect. You can also use different easing curves to further customize the animation.
Best Practices
- Use Meaningful Animations: Animations should enhance the user experience, not distract from it.
- Keep Animations Short: Long animations can be frustrating. Aim for animations that are quick and responsive.
- Test Performance: Ensure animations are smooth and don’t cause performance issues, especially on lower-end devices.
Conclusion
AnimatedVisibility
in Jetpack Compose provides a powerful and flexible way to add engaging transitions to your Android UIs. By combining different transition effects and customizing their durations and easing, you can create a polished and intuitive user experience. Experiment with different animations to find the best fit for your application and delight your users with smooth and meaningful transitions.