Что такое AnimatedVisibility и как он работает?
AnimatedVisibility анимирует появление и скрытие composable по булевому флагу visible. Дочерний контент удерживается в composition до конца exit-анимации. Поддерживает комбинирование fadeIn, slideIn, expandVertically и других transitions через оператор +.
Что такое AnimatedVisibility
AnimatedVisibility — composable-обёртка, которая анимирует появление и скрытие дочернего контента на основе булевого параметра visible. В отличие от простого if (visible) { ... }, компонент удерживает дочерний composable в дереве composition до полного завершения exit-анимации, после чего удаляет его. Это гарантирует, что пользователь видит плавный переход, а не мгновенное исчезновение.
Как работает внутри
Compose отслеживает изменение visible. При переходе false → true запускается EnterTransition; при true → false — ExitTransition. Пока exit-анимация не завершена, content остаётся в composition в специальном состоянии ExitAnimationInProgress. Система transitions строится на Transition<Boolean> под капотом, что позволяет комбинировать несколько эффектов через +.
Стандартные варианты transitions:
fadeIn() + slideInVertically()— плавное появление со сдвигомexpandVertically() / shrinkVertically()— раскрытие/схлопывание по высотеscaleIn() / scaleOut()— масштабирование
Пример
@Composable
fun NotificationBanner(visible: Boolean, message: String) {
AnimatedVisibility(
visible = visible,
enter = fadeIn(animationSpec = tween(300)) + slideInVertically(
initialOffsetY = { -it }
),
exit = fadeOut(animationSpec = tween(200)) + slideOutVertically(
targetOffsetY = { -it }
)
) {
Surface(
color = MaterialTheme.colorScheme.primaryContainer,
modifier = Modifier.fillMaxWidth().padding(8.dp)
) {
Text(
text = message,
modifier = Modifier.padding(16.dp)
)
}
}
}
// Использование:
var showBanner by remember { mutableStateOf(false) }
Column {
NotificationBanner(visible = showBanner, message = "Сохранено")
Button(onClick = { showBanner = !showBanner }) {
Text("Переключить")
}
}
AnimatedContent vs AnimatedVisibility
Если нужно анимировать смену содержимого (например, переключение между двумя виджетами), используют AnimatedContent. AnimatedVisibility работает только с одним булевым условием показа/скрытия.
Подводные камни
- Cleanup в exit-фазе. Если дочерний composable освобождает ресурсы в
DisposableEffect, cleanup произойдёт только после завершения exit-анимации, а не в моментvisible = false. Это важно при работе с камерой, медиаплеером или сетевыми соединениями. - Состояние внутри content.
remember-состояние внутриAnimatedVisibilityсохраняется, пока идёт exit-анимация. После удаления из composition состояние сбрасывается — не полагайтесь на него после скрытия. - Вложенная AnimatedVisibility. Дочерние composable могут использовать
animateEnterExit()modifier для независимой анимации внутри родительского перехода, но легко запутаться в порядке запуска. - Производительность сложных transitions. Комбинирование 3+ transitions одновременно увеличивает нагрузку на rendering. Профилируйте через Android Studio GPU Profiler.
- Доступность.
AnimatedVisibilityне добавляет автоматическиsemantics-аннотации для screen reader. Скрытый контент сvisible = falseнедоступен, но в момент анимации — доступен. Явно управляйтеModifier.semantics { invisibleToUser() }при необходимости. - Лайаут до появления. До первого показа composable не занимает место в лайауте, но после первого скрытия (exit-анимация) он ещё занимает место. Это может вызывать скачки лайаута, если родитель адаптирует размер.
- key и идентичность. При использовании внутри
LazyColumnкаждая строка сAnimatedVisibilityдолжна иметь стабильныйkey, иначе Compose может переиспользовать composable и пропустить анимацию. - Нет out-of-the-box spring для visibility. По умолчанию используется
tween. Для spring-анимации нужно явно передатьspring()вanimationSpecкаждого перехода.
Common mistakes
- Объяснять «AnimatedVisibility» только как синтаксис и не описывать поведение runtime/compiler.
- Игнорировать важный риск: Если хранить resource cleanup только в исчезающем child без учета exit, можно получить неожиданный момент освобождения.
- Давать пример без edge case: отмены, null, recomposition, platform boundary или ошибки.
What the interviewer is testing
- Формулирует суть темы «AnimatedVisibility» своими словами и связывает ее с кодом.
- Называет механизм: Он удерживает content в composition до завершения exit animation и позволяет комбинировать enter/exit transitions.
- Видит production-последствие: Если хранить resource cleanup только в исчезающем child без учета exit, можно получить неожиданный момент освобождения.