AnimatedVisibility
@Composable
public fun AnimatedVisibility(
visible: Boolean,
modifier: Modifier = Modifier,
enter: EnterTransition = fadeIn() + expandIn(),
exit: ExitTransition = shrinkOut() + fadeOut(),
label: String = "AnimatedVisibility",
content: @Composable() AnimatedVisibilityScope.() -> Unit,
)
AnimatedVisibility
composable animates the appearance and disappearance of its content, as
visible
value changes. Different EnterTransition
s and ExitTransition
s can be defined in
enter
and exit
for the appearance and disappearance animation. There are 4 types of
EnterTransition
and ExitTransition
: Fade, Expand/Shrink, Scale and Slide. The enter
transitions can be combined using +
. Same for exit transitions. The order of the combination
does not matter, as the transition animations will start simultaneously. See EnterTransition
and ExitTransition
for details on the three types of transition.
Aside from these three types of EnterTransition
and ExitTransition
, AnimatedVisibility
also
supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
Transition<EnterExitState>
object from the AnimatedVisibilityScope
(i.e.
AnimatedVisibilityScope.transition
). See the second sample code snippet below for example.
These custom animations will be running alongside of the built-in animations specified in enter
and exit
. In cases where the enter/exit animation needs to be completely customized, enter
and/or exit
can be specified as EnterTransition.None
and/or ExitTransition.None
as needed.
AnimatedVisibility
will wait until all of enter/exit animations to finish before it considers
itself idle. content
will only be removed after all the (built-in and custom) exit animations
have finished.
AnimatedVisibility
creates a custom Layout
for its content. The size of the custom layout is
determined by the largest width and largest height of the children. All children will be aligned
to the top start of the Layout
.
Note: Once the exit transition is finished, the content
composable will be removed from the
tree, and disposed. If there's a need to observe the state change of the enter/exit transition
and follow up additional action (e.g. remove data, sequential animation, etc), consider the
AnimatedVisibility API variant that takes a MutableTransitionState
parameter.
By default, the enter transition will be a combination of fadeIn
and expandIn
of the content
from the bottom end. And the exit transition will be shrinking the content towards the bottom end
while fading out (i.e. fadeOut
+ shrinkOut
). The expanding and shrinking will likely also
animate the parent and siblings if they rely on the size of appearing/disappearing content. When
the AnimatedVisibility
composable is put in a Row
or a Column
, the default enter and exit
transitions are tailored to that particular container. See RowScope.AnimatedVisibility
and
ColumnScope.AnimatedVisibility
for details.
Here are two examples of AnimatedVisibility
: one using the built-in enter/exit transition, the
other using a custom enter/exit animation.
The example blow shows how a custom enter/exit animation can be created using the Transition
object (i.e. TransitionAnimatedVisibilityScope
.
Parameters
visible | defines whether the content should be visible |
modifier | modifier for the Layout created to contain the content |
enter | EnterTransition(s) used for the appearing animation, fading in while expanding by default |
exit | ExitTransition(s) used for the disappearing animation, fading out while shrinking by default |
label | A label to differentiate from other animations in Android Studio animation preview. |
content | Content to appear or disappear based on the value of visible |
@Composable
public fun RowScope.AnimatedVisibility(
visible: Boolean,
modifier: Modifier = Modifier,
enter: EnterTransition = fadeIn() + expandHorizontally(),
exit: ExitTransition = fadeOut() + shrinkHorizontally(),
label: String = "AnimatedVisibility",
content: @Composable() AnimatedVisibilityScope.() -> Unit,
)
RowScope.AnimatedVisibility
composable animates the appearance and disappearance of its content
when the AnimatedVisibility
is in a Row
. The default animations are tailored specific to the
Row
layout. See more details below.
Different EnterTransition
s and ExitTransition
s can be defined in enter
and exit
for the
appearance and disappearance animation. There are 4 types of EnterTransition
and
ExitTransition
: Fade, Expand/Shrink, Scale, and Slide. The enter transitions can be combined
using +
. Same for exit transitions. The order of the combination does not matter, as the
transition animations will start simultaneously. See EnterTransition
and ExitTransition
for
details on the three types of transition.
The default enter
and exit
transition is configured based on the horizontal layout of a
Row
. enter
defaults to a combination of fading in and expanding the content horizontally.
(The end of the content will be the leading edge as the content expands to its full width.) And
exit
defaults to shrinking the content horizontally with the end of the content being the
leading edge while fading out. The expanding and shrinking will likely also animate the parent
and siblings in the row since they rely on the size of appearing/disappearing content.
Aside from these three types of EnterTransition
and ExitTransition
, AnimatedVisibility
also
supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
Transition<EnterExitState>
object from the AnimatedVisibilityScope
(i.e.
AnimatedVisibilityScope.transition
). See EnterExitState
for an example of custom animations.
These custom animations will be running along side of the built-in animations specified in
enter
and exit
. In cases where the enter/exit animation needs to be completely customized,
enter
and/or exit
can be specified as EnterTransition.None
and/or ExitTransition.None
as
needed. AnimatedVisibility
will wait until all of enter/exit animations to finish before it
considers itself idle. content
will only be removed after all the (built-in and custom) exit
animations have finished.
AnimatedVisibility
creates a custom Layout
for its content. The size of the custom layout is
determined by the largest width and largest height of the children. All children will be aligned
to the top start of the Layout
.
Note: Once the exit transition is finished, the content
composable will be removed from the
tree, and disposed. If there's a need to observe the state change of the enter/exit transition
and follow up additional action (e.g. remove data, sequential animation, etc), consider the
AnimatedVisibility API variant that takes a MutableTransitionState
parameter.
Here's an example of using RowScope.AnimatedVisibility
in a Row
:
Parameters
visible | defines whether the content should be visible |
modifier | modifier for the Layout created to contain the content |
enter | EnterTransition(s) used for the appearing animation, fading in while expanding horizontally by default |
exit | ExitTransition(s) used for the disappearing animation, fading out while shrinking horizontally by default |
label | A label to differentiate from other animations in Android Studio animation preview. |
content | Content to appear or disappear based on the value of visible |
@Composable
public fun ColumnScope.AnimatedVisibility(
visible: Boolean,
modifier: Modifier = Modifier,
enter: EnterTransition = fadeIn() + expandVertically(),
exit: ExitTransition = fadeOut() + shrinkVertically(),
label: String = "AnimatedVisibility",
content: @Composable AnimatedVisibilityScope.() -> Unit,
)
ColumnScope.AnimatedVisibility
composable animates the appearance and disappearance of its
content when the AnimatedVisibility
is in a Column
. The default animations are tailored
specific to the Column
layout. See more details below.
Different EnterTransition
s and ExitTransition
s can be defined in enter
and exit
for the
appearance and disappearance animation. There are 4 types of EnterTransition
and
ExitTransition
: Fade, Expand/Shrink, Scale and Slide. The enter transitions can be combined
using +
. Same for exit transitions. The order of the combination does not matter, as the
transition animations will start simultaneously. See EnterTransition
and ExitTransition
for
details on the three types of transition.
The default enter
and exit
transition is configured based on the vertical layout of a
Column
. enter
defaults to a combination of fading in and expanding the content vertically.
(The bottom of the content will be the leading edge as the content expands to its full height.)
And the exit
defaults to shrinking the content vertically with the bottom of the content being
the leading edge while fading out. The expanding and shrinking will likely also animate the
parent and siblings in the column since they rely on the size of appearing/disappearing content.
Aside from these three types of EnterTransition
and ExitTransition
, AnimatedVisibility
also
supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
Transition<EnterExitState>
object from the AnimatedVisibilityScope
(i.e.
AnimatedVisibilityScope.transition
). See EnterExitState
for an example of custom animations.
These custom animations will be running along side of the built-in animations specified in
enter
and exit
. In cases where the enter/exit animation needs to be completely customized,
enter
and/or exit
can be specified as EnterTransition.None
and/or ExitTransition.None
as
needed. AnimatedVisibility
will wait until all of enter/exit animations to finish before it
considers itself idle. content
will only be removed after all the (built-in and custom) exit
animations have finished.
AnimatedVisibility
creates a custom Layout
for its content. The size of the custom layout is
determined by the largest width and largest height of the children. All children will be aligned
to the top start of the Layout
.
Note: Once the exit transition is finished, the content
composable will be removed from the
tree, and disposed. If there's a need to observe the state change of the enter/exit transition
and follow up additional action (e.g. remove data, sequential animation, etc), consider the
AnimatedVisibility API variant that takes a MutableTransitionState
parameter.
Here's an example of using ColumnScope.AnimatedVisibility
in a Column
:
Parameters
visible | defines whether the content should be visible |
modifier | modifier for the Layout created to contain the content |
enter | EnterTransition(s) used for the appearing animation, fading in while expanding vertically by default |
exit | ExitTransition(s) used for the disappearing animation, fading out while shrinking vertically by default |
label | A label to differentiate from other animations in Android Studio animation preview. |
content | Content to appear or disappear based on the value of visible |
@Composable
public fun AnimatedVisibility(
visibleState: MutableTransitionState<Boolean>,
modifier: Modifier = Modifier,
enter: EnterTransition = fadeIn() + expandIn(),
exit: ExitTransition = fadeOut() + shrinkOut(),
label: String = "AnimatedVisibility",
content: @Composable() AnimatedVisibilityScope.() -> Unit,
)
AnimatedVisibility
composable animates the appearance and disappearance of its content, as
visibleState
's targetState
changes. The visibleState
can also be used to observe the state of AnimatedVisibility
. For example: visibleState.isIdle
indicates whether all the animations have finished in AnimatedVisibility
, and
visibleState.currentState
returns the initial state of the current animations.
Different EnterTransition
s and ExitTransition
s can be defined in enter
and exit
for the
appearance and disappearance animation. There are 4 types of EnterTransition
and
ExitTransition
: Fade, Expand/Shrink, Scale and Slide. The enter transitions can be combined
using +
. Same for exit transitions. The order of the combination does not matter, as the
transition animations will start simultaneously. See EnterTransition
and ExitTransition
for
details on the three types of transition.
Aside from these three types of EnterTransition
and ExitTransition
, AnimatedVisibility
also
supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
Transition<EnterExitState>
object from the AnimatedVisibilityScope
(i.e.
AnimatedVisibilityScope.transition
). See EnterExitState
for an example of custom animations.
These custom animations will be running along side of the built-in animations specified in
enter
and exit
. In cases where the enter/exit animation needs to be completely customized,
enter
and/or exit
can be specified as EnterTransition.None
and/or ExitTransition.None
as
needed. AnimatedVisibility
will wait until all of enter/exit animations to finish before it
considers itself idle. content
will only be removed after all the (built-in and custom) exit
animations have finished.
AnimatedVisibility
creates a custom Layout
for its content. The size of the custom layout is
determined by the largest width and largest height of the children. All children will be aligned
to the top start of the Layout
.
Note: Once the exit transition is finished, the content
composable will be removed from the
tree, and disposed. Both currentState
and targetState
will be false
for visibleState
.
By default, the enter transition will be a combination of fadeIn
and expandIn
of the content
from the bottom end. And the exit transition will be shrinking the content towards the bottom end
while fading out (i.e. fadeOut
+ shrinkOut
). The expanding and shrinking will likely also
animate the parent and siblings if they rely on the size of appearing/disappearing content. When
the AnimatedVisibility
composable is put in a Row
or a Column
, the default enter and exit
transitions are tailored to that particular container. See RowScope.AnimatedVisibility
and
ColumnScope.AnimatedVisibility
for details.
Parameters
visibleState | defines whether the content should be visible |
modifier | modifier for the Layout created to contain the content |
enter | EnterTransition(s) used for the appearing animation, fading in while expanding by default |
exit | ExitTransition(s) used for the disappearing animation, fading out while shrinking by default |
label | A label to differentiate from other animations in Android Studio animation preview. |
content | Content to appear or disappear based on the value of visibleState |
@Composable
public fun RowScope.AnimatedVisibility(
visibleState: MutableTransitionState<Boolean>,
modifier: Modifier = Modifier,
enter: EnterTransition = expandHorizontally() + fadeIn(),
exit: ExitTransition = shrinkHorizontally() + fadeOut(),
label: String = "AnimatedVisibility",
content: @Composable() AnimatedVisibilityScope.() -> Unit,
)
RowScope.AnimatedVisibility
composable animates the appearance and disappearance of its content
as visibleState
's targetState
changes. The default
enter
and exit
transitions are tailored specific to the Row
layout. See more details below.
The visibleState
can also be used to observe the state of AnimatedVisibility
. For example:
visibleState.isIdle
indicates whether all the animations have finished in AnimatedVisibility
,
and visibleState.currentState
returns the initial state of the current animations.
Different EnterTransition
s and ExitTransition
s can be defined in enter
and exit
for the
appearance and disappearance animation. There are 4 types of EnterTransition
and
ExitTransition
: Fade, Expand/Shrink, Scale and Slide. The enter transitions can be combined
using +
. Same for exit transitions. The order of the combination does not matter, as the
transition animations will start simultaneously. See EnterTransition
and ExitTransition
for
details on the three types of transition.
The default enter
and exit
transition is configured based on the horizontal layout of a
Row
. enter
defaults to a combination of fading in and expanding the content horizontally.
(The end of the content will be the leading edge as the content expands to its full width.) And
exit
defaults to shrinking the content horizontally with the end of the content being the
leading edge while fading out. The expanding and shrinking will likely also animate the parent
and siblings in the row since they rely on the size of appearing/disappearing content.
Aside from these three types of EnterTransition
and ExitTransition
, AnimatedVisibility
also
supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
Transition<EnterExitState>
object from the AnimatedVisibilityScope
(i.e.
AnimatedVisibilityScope.transition
). See EnterExitState
for an example of custom animations.
These custom animations will be running along side of the built-in animations specified in
enter
and exit
. In cases where the enter/exit animation needs to be completely customized,
enter
and/or exit
can be specified as EnterTransition.None
and/or ExitTransition.None
as
needed. AnimatedVisibility
will wait until all of enter/exit animations to finish before it
considers itself idle. content
will only be removed after all the (built-in and custom) exit
animations have finished.
AnimatedVisibility
creates a custom Layout
for its content. The size of the custom layout is
determined by the largest width and largest height of the children. All children will be aligned
to the top start of the Layout
.
Note: Once the exit transition is finished, the content
composable will be removed from the
tree, and disposed. Both currentState
and targetState
will be false
for visibleState
.
Parameters
visibleState | defines whether the content should be visible |
modifier | modifier for the Layout created to contain the content |
enter | EnterTransition(s) used for the appearing animation, fading in while expanding vertically by default |
exit | ExitTransition(s) used for the disappearing animation, fading out while shrinking vertically by default |
label | A label to differentiate from other animations in Android Studio animation preview. |
content | Content to appear or disappear based on the value of visibleState |
@Composable
public fun ColumnScope.AnimatedVisibility(
visibleState: MutableTransitionState<Boolean>,
modifier: Modifier = Modifier,
enter: EnterTransition = expandVertically() + fadeIn(),
exit: ExitTransition = shrinkVertically() + fadeOut(),
label: String = "AnimatedVisibility",
content: @Composable() AnimatedVisibilityScope.() -> Unit,
)
ColumnScope.AnimatedVisibility
composable animates the appearance and disappearance of its
content as visibleState
's targetState
changes. The
default enter
and exit
transitions are tailored specific to the Column
layout. See more
details below. The visibleState
can also be used to observe the state of AnimatedVisibility
.
For example: visibleState.isIdle
indicates whether all the animations have finished in
AnimatedVisibility
, and visibleState.currentState
returns the initial state of the current
animations.
Different EnterTransition
s and ExitTransition
s can be defined in enter
and exit
for the
appearance and disappearance animation. There are 4 types of EnterTransition
and
ExitTransition
: Fade, Expand/Shrink, Scale and Slide. The enter transitions can be combined
using +
. Same for exit transitions. The order of the combination does not matter, as the
transition animations will start simultaneously. See EnterTransition
and ExitTransition
for
details on the three types of transition.
The default enter
and exit
transition is configured based on the vertical layout of a
Column
. enter
defaults to a combination of fading in and expanding the content vertically.
(The bottom of the content will be the leading edge as the content expands to its full height.)
And the exit
defaults to shrinking the content vertically with the bottom of the content being
the leading edge while fading out. The expanding and shrinking will likely also animate the
parent and siblings in the column since they rely on the size of appearing/disappearing content.
Aside from these three types of EnterTransition
and ExitTransition
, AnimatedVisibility
also
supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
Transition<EnterExitState>
object from the AnimatedVisibilityScope
(i.e.
AnimatedVisibilityScope.transition
). See EnterExitState
for an example of custom animations.
These custom animations will be running along side of the built-in animations specified in
enter
and exit
. In cases where the enter/exit animation needs to be completely customized,
enter
and/or exit
can be specified as EnterTransition.None
and/or ExitTransition.None
as
needed. AnimatedVisibility
will wait until all of enter/exit animations to finish before it
considers itself idle. content
will only be removed after all the (built-in and custom) exit
animations have finished.
AnimatedVisibility
creates a custom Layout
for its content. The size of the custom layout is
determined by the largest width and largest height of the children. All children will be aligned
to the top start of the Layout
.
Note: Once the exit transition is finished, the content
composable will be removed from the
tree, and disposed. Both currentState
and targetState
will be false
for visibleState
.
Parameters
visibleState | defines whether the content should be visible |
modifier | modifier for the Layout created to contain the content |
enter | EnterTransition(s) used for the appearing animation, fading in while expanding vertically by default |
exit | ExitTransition(s) used for the disappearing animation, fading out while shrinking vertically by default |
label | A label to differentiate from other animations in Android Studio animation preview. |
content | Content to appear or disappear based on of visibleState |
@Composable
public fun <T> Transition<T>.AnimatedVisibility(
visible: (T) -> Boolean,
modifier: Modifier = Modifier,
enter: EnterTransition = fadeIn() + expandIn(),
exit: ExitTransition = shrinkOut() + fadeOut(),
content: @Composable() AnimatedVisibilityScope.() -> Unit,
): Unit
This extension function creates an AnimatedVisibility
composable as a child Transition of the
given Transition. This means: 1) the enter/exit transition is now triggered by the provided
Transition
's targetState
change. When the targetState changes, the
visibility will be derived using the visible
lambda and Transition.targetState
. 2) The
enter/exit transitions, as well as any custom enter/exit animations defined in
AnimatedVisibility
are now hoisted to the parent Transition. The parent Transition will wait
for all of them to finish before it considers itself finished (i.e. Transition.currentState
=
Transition.targetState
), and subsequently removes the content in the exit case.
Different EnterTransition
s and ExitTransition
s can be defined in enter
and exit
for the
appearance and disappearance animation. There are 4 types of EnterTransition
and
ExitTransition
: Fade, Expand/Shrink, Scale and Slide. The enter transitions can be combined
using +
. Same for exit transitions. The order of the combination does not matter, as the
transition animations will start simultaneously. See EnterTransition
and ExitTransition
for
details on the three types of transition.
Aside from these three types of EnterTransition
and ExitTransition
, AnimatedVisibility
also
supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
Transition<EnterExitState>
object from the AnimatedVisibilityScope
(i.e.
AnimatedVisibilityScope.transition
). See EnterExitState
for an example of custom animations.
These custom animations will be running along side of the built-in animations specified in
enter
and exit
. In cases where the enter/exit animation needs to be completely customized,
enter
and/or exit
can be specified as EnterTransition.None
and/or ExitTransition.None
as
needed. AnimatedVisibility
will wait until all of enter/exit animations to finish before it
considers itself idle. content
will only be removed after all the (built-in and custom) exit
animations have finished.
AnimatedVisibility
creates a custom Layout
for its content. The size of the custom layout is
determined by the largest width and largest height of the children. All children will be aligned
to the top start of the Layout
.
Note: Once the exit transition is finished, the content
composable will be removed from the
tree, and disposed.
By default, the enter transition will be a combination of fadeIn
and expandIn
of the content
from the bottom end. And the exit transition will be shrinking the content towards the bottom end
while fading out (i.e. fadeOut
+ shrinkOut
). The expanding and shrinking will likely also
animate the parent and siblings if they rely on the size of appearing/disappearing content.
Parameters
visible | defines whether the content should be visible based on transition state T |
modifier | modifier for the Layout created to contain the content |
enter | EnterTransition(s) used for the appearing animation, fading in while expanding vertically by default |
exit | ExitTransition(s) used for the disappearing animation, fading out while shrinking vertically by default |
content | Content to appear or disappear based on the visibility derived from the Transition.targetState and the provided visible lambda |
Code Examples
FullyLoadedTransition
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun FullyLoadedTransition() {
var visible by remember { mutableStateOf(true) }
AnimatedVisibility(
visible = visible,
enter =
slideInVertically(
// Start the slide from 40 (pixels) above where the content is supposed to go, to
// produce a parallax effect
initialOffsetY = { -40 }
) +
expandVertically(expandFrom = Alignment.Top) +
scaleIn(
// Animate scale from 0f to 1f using the top center as the pivot point.
transformOrigin = TransformOrigin(0.5f, 0f)
) +
fadeIn(initialAlpha = 0.3f),
exit = slideOutVertically() + shrinkVertically() + fadeOut() + scaleOut(targetScale = 1.2f),
) {
// Content that needs to appear/disappear goes here:
Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp))
}
}
AnimatedVisibilityWithBooleanVisibleParamNoReceiver
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AnimatedVisibilityWithBooleanVisibleParamNoReceiver() {
var visible by remember { mutableStateOf(true) }
Box(modifier = Modifier.clickable { visible = !visible }) {
AnimatedVisibility(
visible = visible,
modifier = Modifier.align(Alignment.Center),
enter = fadeIn(),
exit = fadeOut(animationSpec = tween(200)) + scaleOut(),
) { // Content that needs to appear/disappear goes here:
// Here we can optionally define a custom enter/exit animation by creating an animation
// using the Transition<EnterExitState> object from AnimatedVisibilityScope:
// As a part of the enter transition, the corner radius will be animated from 0.dp to
// 50.dp.
val cornerRadius by
transition.animateDp {
when (it) {
EnterExitState.PreEnter -> 0.dp
EnterExitState.Visible -> 50.dp
// No corner radius change when exiting.
EnterExitState.PostExit -> 50.dp
}
}
Box(
Modifier.background(Color.Red, shape = RoundedCornerShape(cornerRadius))
.height(100.dp)
.fillMaxWidth()
)
}
}
}
AnimatedFloatingActionButton
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun ColumnScope.AnimatedFloatingActionButton() {
var expanded by remember { mutableStateOf(true) }
FloatingActionButton(
onClick = { expanded = !expanded },
modifier = Modifier.align(Alignment.CenterHorizontally),
) {
Row(Modifier.padding(start = 12.dp, end = 12.dp)) {
Icon(
Icons.Default.Favorite,
contentDescription = "Favorite",
modifier = Modifier.align(Alignment.CenterVertically),
)
AnimatedVisibility(expanded, modifier = Modifier.align(Alignment.CenterVertically)) {
Text(modifier = Modifier.padding(start = 12.dp), text = "Favorite")
}
}
}
Spacer(Modifier.requiredHeight(20.dp))
}
ColumnAnimatedVisibilitySample
@Composable
fun ColumnAnimatedVisibilitySample() {
var itemIndex by remember { mutableStateOf(0) }
val colors = listOf(Color.Red, Color.Green, Color.Blue)
Column(Modifier.fillMaxWidth().clickable { itemIndex = (itemIndex + 1) % colors.size }) {
colors.forEachIndexed { i, color ->
// By default ColumnScope.AnimatedVisibility expands and shrinks new content while
// fading.
AnimatedVisibility(i <= itemIndex) {
Box(Modifier.requiredHeight(40.dp).fillMaxWidth().background(color))
}
}
}
}
AnimatedVisibilityLazyColumnSample
@Composable
fun AnimatedVisibilityLazyColumnSample() {
val turquoiseColors =
listOf(
Color(0xff07688C),
Color(0xff1986AF),
Color(0xff50B6CD),
Color(0xffBCF8FF),
Color(0xff8AEAE9),
Color(0xff46CECA),
)
// MyModel class handles the data change of the items that are displayed in LazyColumn.
class MyModel {
private val _items: MutableList<ColoredItem> = mutableStateListOf()
private var lastItemId = 0
val items: List<ColoredItem> = _items
// Each item has a MutableTransitionState field to track as well as to mutate the item's
// visibility. When the MutableTransitionState's targetState changes, corresponding
// transition will be fired. MutableTransitionState allows animation lifecycle to be
// observed through it's [currentState] and [isIdle]. See below for details.
inner class ColoredItem(val visible: MutableTransitionState<Boolean>, val itemId: Int) {
val color: Color
get() = turquoiseColors.let { it[itemId % it.size] }
}
fun addNewItem() {
lastItemId++
_items.add(
ColoredItem(
// Here the initial state of the MutableTransitionState is set to false, and
// target state is set to true. This will result in an enter transition for
// the newly added item.
MutableTransitionState(false).apply { targetState = true },
lastItemId,
)
)
}
fun removeItem(item: ColoredItem) {
// By setting the targetState to false, this will effectively trigger an exit
// animation in AnimatedVisibility.
item.visible.targetState = false
}
fun pruneItems() {
// Inspect the animation status through MutableTransitionState. If isIdle == true,
// all animations have finished for the transition.
_items.removeAll(
items.filter {
// This checks that the animations have finished && the animations are exit
// transitions. In other words, the item has finished animating out.
it.visible.isIdle && !it.visible.targetState
}
)
}
fun removeAll() {
_items.forEach { it.visible.targetState = false }
}
}
@Composable
fun AnimatedVisibilityInLazyColumn() {
Column {
val model = remember { MyModel() }
Row(Modifier.fillMaxWidth()) {
Button({ model.addNewItem() }, modifier = Modifier.padding(15.dp).weight(1f)) {
Text("Add")
}
}
// This sets up a flow to check whether any item has finished animating out. If yes,
// notify the model to prune the list.
LaunchedEffect(model) {
snapshotFlow {
model.items.firstOrNull { it.visible.isIdle && !it.visible.targetState }
}
.collect {
if (it != null) {
model.pruneItems()
}
}
}
LazyColumn {
items(model.items, key = { it.itemId }) { item ->
AnimatedVisibility(
item.visible,
enter = expandVertically(),
exit = shrinkVertically(),
) {
Box(Modifier.fillMaxWidth().requiredHeight(90.dp).background(item.color)) {
Button(
{ model.removeItem(item) },
modifier = Modifier.align(Alignment.CenterEnd).padding(15.dp),
) {
Text("Remove")
}
}
}
}
}
Button({ model.removeAll() }, modifier = Modifier.align(Alignment.End).padding(15.dp)) {
Text("Clear All")
}
}
}
}
AVColumnScopeWithMutableTransitionState
@Composable
fun AVColumnScopeWithMutableTransitionState() {
var visible by remember { mutableStateOf(true) }
val colors = remember { listOf(Color(0xff2a9d8f), Color(0xffe9c46a), Color(0xfff4a261)) }
Column {
repeat(3) {
AnimatedVisibility(
visibleState =
remember {
// This sets up the initial state of the AnimatedVisibility to false to
// guarantee an initial enter transition. In contrast, initializing this
// as
// `MutableTransitionState(visible)` would result in no initial enter
// transition.
MutableTransitionState(initialState = false)
}
.apply {
// This changes the target state of the visible state. If it's different
// than
// the initial state, an enter/exit transition will be triggered.
targetState = visible
}
) { // Content that needs to appear/disappear goes here:
Box(Modifier.fillMaxWidth().height(100.dp).background(colors[it]))
}
}
}
}
AddAnimatedVisibilityToGenericTransitionSample
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AddAnimatedVisibilityToGenericTransitionSample() {
@Composable
fun ItemMainContent() {
Row(Modifier.height(100.dp).fillMaxWidth(), Arrangement.SpaceEvenly) {
Box(
Modifier.size(60.dp)
.align(Alignment.CenterVertically)
.background(Color(0xffcdb7f6), CircleShape)
)
Column(Modifier.align(Alignment.CenterVertically)) {
Box(Modifier.height(30.dp).width(300.dp).padding(5.dp).background(Color.LightGray))
Box(Modifier.height(30.dp).width(300.dp).padding(5.dp).background(Color.LightGray))
}
}
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun SelectableItem() {
// This sample animates a number of properties, including AnimatedVisibility, as a part of
// the Transition going between selected and unselected.
Box(Modifier.padding(15.dp)) {
var selected by remember { mutableStateOf(false) }
// Creates a transition to animate visual changes when `selected` is changed.
val selectionTransition = updateTransition(selected)
// Animates the border color as a part of the transition
val borderColor by
selectionTransition.animateColor { isSelected ->
if (isSelected) Color(0xff03a9f4) else Color.White
}
// Animates the background color when selected state changes
val contentBackground by
selectionTransition.animateColor { isSelected ->
if (isSelected) Color(0xffdbf0fe) else Color.White
}
// Animates elevation as a part of the transition
val elevation by
selectionTransition.animateDp { isSelected -> if (isSelected) 10.dp else 2.dp }
Surface(
shape = RoundedCornerShape(10.dp),
border = BorderStroke(2.dp, borderColor),
modifier = Modifier.clickable { selected = !selected },
color = contentBackground,
elevation = elevation,
) {
Column(Modifier.fillMaxWidth()) {
ItemMainContent()
// Creates an AnimatedVisibility as a part of the transition, so that when
// selected it's visible. This will hoist all the animations that are internal
// to AnimatedVisibility (i.e. fade, slide, etc) to the transition. As a result,
// `selectionTransition` will not finish until all the animations in
// AnimatedVisibility as well as animations added directly to it have finished.
selectionTransition.AnimatedVisibility(
visible = { it },
enter = expandVertically(),
exit = shrinkVertically(),
) {
Box(Modifier.fillMaxWidth().padding(10.dp)) {
Text(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed" +
" eiusmod tempor incididunt labore et dolore magna aliqua. " +
"Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
"laboris nisi ut aliquip ex ea commodo consequat. Duis aute " +
"irure dolor."
)
}
}
}
}
}
}
}