시배's Android
Compose Docs | Animation modifiers and composables 본문
Animation modifiers and composables | Jetpack Compose | Android Developers
Animation modifiers and composables Stay organized with collections Save and categorize content based on your preferences. Compose comes with built-in composables and modifiers for handling common animation use cases. Built-in animated composables Animate
developer.android.com
Built-in animated composables
Animate appearance and disappearance with AnimatedVisibility
AnimatedVisibility 컴포저블은 콘텐츠의 모양과 사라짐을 애니메이션으로 표현합니다.
var editable by remember { mutableStateOf(true) }
AnimatedVisibility(visible = editable) {
Text(text = "Edit")
}
기본적으로 콘텐츠는 페이드 인 및 확장으로 나타나고 페이드 아웃 및 축소로 사라집니다. 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 |
fadeIn![]() |
fadeOut![]() |
slideIn![]() |
slideOut![]() |
slideInHorizontally![]() |
slideOutHorizontally![]() |
slideInVertically![]() |
slideOutVertically![]() |
scaleIn![]() |
scaleOut![]() |
expandIn![]() |
shrinkOut![]() |
expandHorizontally![]() |
shrinkHorizontally![]() |
expandVertically![]() |
shrinkVertically![]() |
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"
}
)
}
Animate enter and exit for children
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…
}
}
}
경우에 따라 애니메이션이 전혀 적용되지 않도록 하여 자식들이 각각 고유한 애니메이션을 animateEnterExit에 의해 가질 수 있도록 하고 싶을 수 있습니다. 이렇게 하려면 AnimatedVisibility 컴포저블에서 EnterTransition.None 및 ExitTransition.None을 지정하면 됩니다.
Add custom animation
내장된 시작 및 종료 애니메이션 외에 커스텀 애니메이션 효과를 추가하려면 AnimatedVisibility에 대한 콘텐츠 람다 내부의 transition 속성을 통해 기본 트랜지션 인스턴스에 액세스하세요. 트랜지션 인스턴스에 추가된 모든 애니메이션 상태는 AnimatedVisibility의 진입 및 종료 애니메이션과 동시에 실행됩니다. AnimatedVisibility는 트랜지션의 모든 애니메이션이 완료될 때까지 기다렸다가 해당 콘텐츠를 제거합니다. 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))
}
Animate based on target state with AnimatedContent
Row {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Add")
}
AnimatedContent(targetState = count) { targetCount ->
// Make sure to use `targetCount`, not `count`.
Text(text = "Count: $targetCount")
}
}
항상 람다 매개변수를 사용하여 콘텐츠에 반영해야 한다는 점에 유의하세요. API는 이 값을 키로 사용하여 현재 표시되는 콘텐츠를 식별합니다.
기본적으로 초기 콘텐츠가 페이드 아웃된 다음 대상 콘텐츠가 페이드 인됩니다(이 동작을 페이드 스루라고 함). transitionSpec 매개 변수에 ContentTransform 객체를 지정하여 이 애니메이션 동작을 사용자 지정할 수 있습니다. with 접두사 함수를 사용하여 엔터 트랜지션과 출구 트랜지션을 결합하여 콘텐츠 트랜스폼을 만들 수 있습니다. SizeTransform을 using 접두사 함수로 연결하여 ContentTransform에 적용할 수 있습니다.
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() with
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() with
slideOutVertically { height -> height } + fadeOut()
}.using(
// Disable clipping since the faded slide-in/out should
// be displayed out of bounds.
SizeTransform(clip = false)
)
}
) { targetCount ->
Text(text = "$targetCount")
}

EnterTransition은 대상 콘텐츠가 어떻게 표시되어야 하는지 정의하고 ExitTransition은 초기 콘텐츠가 어떻게 사라져야 하는지 정의합니다. AnimatedVisibility에 사용할 수 있는 모든 EnterTransition 및 ExitTransition 함수 외에도 AnimatedContent는 slideIntoContainer 및 slideOutOfContainer를 제공합니다. 이 함수는 초기 콘텐츠의 크기와 AnimatedContent 콘텐츠의 대상 콘텐츠에 따라 슬라이드 거리를 계산하는 slideInHorizontally/Vertically 및 slideOutHorizontally/Vertically의 편리한 대안입니다.
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)) with
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
}
}
}
}
) { targetExpanded ->
if (targetExpanded) {
Expanded()
} else {
ContentIcon()
}
}
}

Animate child enter and exit transitions
AnimatedVisibility와 마찬가지로 animateEnterExit 수정자는 AnimatedContent의 콘텐츠 람다 내부에서 사용할 수 있습니다. 이를 사용하여 직접 또는 간접 자식 각각에 EnterAnimation 및 ExitAnimation을 개별적으로 적용할 수 있습니다.
Add custom animation
Animate between two layouts with Crossfade
var currentPage by remember { mutableStateOf("A") }
Crossfade(targetState = currentPage) { screen ->
when (screen) {
"A" -> Text("Page A")
"B" -> Text("Page B")
}
}
Animate composable size changes with animateContentSize
var message by remember { mutableStateOf("Hello") }
Box(
modifier = Modifier.background(Color.Blue).animateContentSize()
) { Text(text = message) }
'Android > Compose Docs' 카테고리의 다른 글
Compose Docs | Understand gestures (0) | 2023.10.30 |
---|---|
Compose Docs | Lists and grids (0) | 2023.09.17 |
Compose Docs | Anatomy of a theme in Compose (0) | 2023.09.16 |
Compose Docs | Custom Design Systems (0) | 2023.09.16 |
Compose Docs | ConstraintLayout (0) | 2023.09.06 |