Compose поставляется со встроенными компонентами и модификаторами для обработки распространенных случаев использования анимации.
Встроенные анимированные составные элементы
Анимируйте появление и исчезновение с помощью AnimatedVisibility

Составной элемент AnimatedVisibility
анимирует появление и исчезновение своего содержимого.
var visible by remember {
mutableStateOf(true)
}
// Animated visibility will eventually remove the item from the composition once the animation has finished.
AnimatedVisibility(visible) {
// your composable here
// ...
}
По умолчанию содержимое появляется путем постепенного появления и расширения, а исчезает — путем постепенного исчезновения и сжатия. Переход можно настроить, указав EnterTransition
и ExitTransition
.
var visible by remember { mutableStateOf(true) }
val density = LocalDensity.current
AnimatedVisibility(
visible = visible,
enter = slideInVertically {
// Slide in from 40 dp from the top.
with(density) { -40.dp.roundToPx() }
} + expandVertically(
// Expand from the top.
expandFrom = Alignment.Top
) + fadeIn(
// Fade in with the initial alpha of 0.3f.
initialAlpha = 0.3f
),
exit = slideOutVertically() + shrinkVertically() + fadeOut()
) {
Text(
"Hello",
Modifier
.fillMaxWidth()
.height(200.dp)
)
}
Как видно в приведенном выше примере, вы можете объединить несколько объектов EnterTransition
или ExitTransition
с помощью оператора +
, и каждый из них принимает дополнительные параметры для настройки своего поведения. См. ссылки для получения дополнительной информации.
Примеры EnterTransition
и ExitTransition
AnimatedVisibility
также предлагает вариант, который принимает MutableTransitionState
. Это позволяет запускать анимацию, как только AnimatedVisibility
добавляется в дерево композиции. Это также полезно для наблюдения за состоянием анимации.
// Create a MutableTransitionState<Boolean> for the AnimatedVisibility.
val state = remember {
MutableTransitionState(false).apply {
// Start the animation immediately.
targetState = true
}
}
Column {
AnimatedVisibility(visibleState = state) {
Text(text = "Hello, world!")
}
// Use the MutableTransitionState to know the current animation state
// of the AnimatedVisibility.
Text(
text = when {
state.isIdle && state.currentState -> "Visible"
!state.isIdle && state.currentState -> "Disappearing"
state.isIdle && !state.currentState -> "Invisible"
else -> "Appearing"
}
)
}
Анимированный вход и выход для детей
Содержимое в AnimatedVisibility
(прямые или косвенные дочерние элементы) может использовать модификатор animateEnterExit
, чтобы указать различное поведение анимации для каждого из них. Визуальный эффект для каждого из этих дочерних элементов представляет собой комбинацию анимаций, указанных в составном компоненте AnimatedVisibility
, и собственных анимаций входа и выхода дочернего элемента.
var visible by remember { mutableStateOf(true) }
AnimatedVisibility(
visible = visible,
enter = fadeIn(),
exit = fadeOut()
) {
// Fade in/out the background and the foreground.
Box(
Modifier
.fillMaxSize()
.background(Color.DarkGray)
) {
Box(
Modifier
.align(Alignment.Center)
.animateEnterExit(
// Slide in/out the inner box.
enter = slideInVertically(),
exit = slideOutVertically()
)
.sizeIn(minWidth = 256.dp, minHeight = 64.dp)
.background(Color.Red)
) {
// Content of the notification…
}
}
}
В некоторых случаях может потребоваться, чтобы AnimatedVisibility
вообще не применял анимацию, чтобы каждый из дочерних элементов мог иметь свою собственную анимацию с помощью animateEnterExit
. Для этого укажите EnterTransition.None
и ExitTransition.None
в компонуемом элементе AnimatedVisibility
.
Добавить пользовательскую анимацию
Если вы хотите добавить пользовательские эффекты анимации помимо встроенных анимаций входа и выхода, получите доступ к базовому экземпляру Transition
через свойство transition
внутри лямбда-выражения содержимого для AnimatedVisibility
. Любые состояния анимации, добавленные в экземпляр Transition, будут выполняться одновременно с анимациями входа и выхода AnimatedVisibility
. AnimatedVisibility
ожидает завершения всех анимаций в Transition
, прежде чем удалять его содержимое. Для анимаций выхода, созданных независимо от Transition
(например, с использованием animate*AsState
), AnimatedVisibility
не сможет их учитывать и, следовательно, может удалить компонуемый контент до их завершения.
var visible by remember { mutableStateOf(true) }
AnimatedVisibility(
visible = visible,
enter = fadeIn(),
exit = fadeOut()
) { // this: AnimatedVisibilityScope
// Use AnimatedVisibilityScope#transition to add a custom animation
// to the AnimatedVisibility.
val background by transition.animateColor(label = "color") { state ->
if (state == EnterExitState.Visible) Color.Blue else Color.Gray
}
Box(
modifier = Modifier
.size(128.dp)
.background(background)
)
}
Подробную информацию о Transition
см. в updateTransition .
Анимация на основе целевого состояния с помощью AnimatedContent
Составной элемент AnimatedContent
анимирует свое содержимое по мере его изменения в зависимости от целевого состояния.
Row {
var count by remember { mutableIntStateOf(0) }
Button(onClick = { count++ }) {
Text("Add")
}
AnimatedContent(
targetState = count,
label = "animated content"
) { targetCount ->
// Make sure to use `targetCount`, not `count`.
Text(text = "Count: $targetCount")
}
}
Обратите внимание, что вы всегда должны использовать параметр лямбда и отражать его в содержимом. API использует это значение как ключ для идентификации отображаемого в данный момент контента.
По умолчанию исходное содержимое исчезает, а затем появляется целевое содержимое (это поведение называется сквозным исчезновением ). Вы можете настроить это поведение анимации, указав объект ContentTransform
в transitionSpec
. Вы можете создать ContentTransform
, объединив EnterTransition
с ExitTransition
используя функцию with
infix. Вы можете применить SizeTransform
к ContentTransform
, присоединив его с помощью функции using
infix.
AnimatedContent(
targetState = count,
transitionSpec = {
// Compare the incoming number with the previous number.
if (targetState > initialState) {
// If the target number is larger, it slides up and fades in
// while the initial (smaller) number slides up and fades out.
slideInVertically { height -> height } + fadeIn() togetherWith
slideOutVertically { height -> -height } + fadeOut()
} else {
// If the target number is smaller, it slides down and fades in
// while the initial number slides down and fades out.
slideInVertically { height -> -height } + fadeIn() togetherWith
slideOutVertically { height -> height } + fadeOut()
}.using(
// Disable clipping since the faded slide-in/out should
// be displayed out of bounds.
SizeTransform(clip = false)
)
}, label = "animated content"
) { targetCount ->
Text(text = "$targetCount")
}
EnterTransition
определяет, как должно выглядеть целевое содержимое, а ExitTransition
определяет, как должно исчезнуть исходное содержимое. В дополнение ко всем функциям EnterTransition
и ExitTransition
, доступным для AnimatedVisibility
, AnimatedContent
предлагает slideIntoContainer
и slideOutOfContainer
. Это удобные альтернативы slideInHorizontally/Vertically
и slideOutHorizontally/Vertically
, которые вычисляют расстояние слайда на основе размеров исходного содержимого и целевого содержимого содержимого AnimatedContent
.
SizeTransform
определяет, как размер должен анимироваться между исходным и целевым содержимым. При создании анимации у вас есть доступ как к начальному, так и к целевому размеру. SizeTransform
также контролирует, должно ли содержимое обрезаться до размера компонента во время анимации.
var expanded by remember { mutableStateOf(false) }
Surface(
color = MaterialTheme.colorScheme.primary,
onClick = { expanded = !expanded }
) {
AnimatedContent(
targetState = expanded,
transitionSpec = {
fadeIn(animationSpec = tween(150, 150)) togetherWith
fadeOut(animationSpec = tween(150)) using
SizeTransform { initialSize, targetSize ->
if (targetState) {
keyframes {
// Expand horizontally first.
IntSize(targetSize.width, initialSize.height) at 150
durationMillis = 300
}
} else {
keyframes {
// Shrink vertically first.
IntSize(initialSize.width, targetSize.height) at 150
durationMillis = 300
}
}
}
}, label = "size transform"
) { targetExpanded ->
if (targetExpanded) {
Expanded()
} else {
ContentIcon()
}
}
}
Анимация переходов входа и выхода ребенка
Как и AnimatedVisibility
, модификатор animateEnterExit
доступен внутри лямбда-выражения содержимого AnimatedContent
. Используйте это, чтобы применить EnterAnimation
и ExitAnimation
к каждому прямому или косвенному дочернему элементу отдельно.
Добавить пользовательскую анимацию
Как и в случае с AnimatedVisibility
, поле transition
доступно внутри лямбда-выражения содержимого AnimatedContent
. Используйте это, чтобы создать собственный эффект анимации, который запускается одновременно с переходом AnimatedContent
. Подробности смотрите в updateTransition .
Анимация между двумя макетами с помощью Crossfade
Crossfade
анимирует переход между двумя макетами с помощью анимации плавного перехода. При переключении значения, переданного current
параметру, содержимое переключается с помощью плавной анимации.
var currentPage by remember { mutableStateOf("A") }
Crossfade(targetState = currentPage, label = "cross fade") { screen ->
when (screen) {
"A" -> Text("Page A")
"B" -> Text("Page B")
}
}
Встроенные модификаторы анимации.
Анимация изменения составного размера с помощью animateContentSize

Модификатор animateContentSize
анимирует изменение размера.
var expanded by remember { mutableStateOf(false) }
Box(
modifier = Modifier
.background(colorBlue)
.animateContentSize()
.height(if (expanded) 400.dp else 200.dp)
.fillMaxWidth()
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null
) {
expanded = !expanded
}
) {
}
Список анимаций элементов
Если вы хотите анимировать переупорядочение элементов внутри ленивого списка или сетки, ознакомьтесь с документацией по анимации элементов ленивого макета .
{% дословно %}Пока рекомендаций нет.
Попытайтесь войти в свой аккаунт Google.