animate*AsState 기초
단일 값을 부드럽게 애니메이션 처리합니다.
animate*AsState 기초은(는) CoddyKit의 무료 Android Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Android Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Android Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
단일 값 애니메이션
Compose에서 애니메이션을 적용하는 가장 간단한 방법은 animate*AsState 계열을 사용하는 것입니다. 목표 값을 전달하면 현재 값에서 목표 값까지 부드럽게 애니메이션되는 State를 반환하며, 목표가 변경될 때마다 애니메이션이 실행됩니다.
일반적으로 사용하는 각 타입에 대응하는 변형이 있습니다. 예를 들어 animateFloatAsState, animateDpAsState, animateColorAsState, animateOffsetAsState 등이 있습니다.
animateFloatAsState
animateFloatAsState는 하나의 Float를 애니메이션으로 변경합니다. 일반적인 사용 예는 불투명도(alpha)입니다. visible이 전환되면 반환된 alpha가 0f와 1f 사이를 부드럽게 이동합니다.
by 키워드에도 주목하세요. 이 키워드를 사용하면 애니메이션되는 State<Float>를 일반 Float처럼 직접 읽을 수 있습니다.
@Composable
fun FadingLabel(visible: Boolean) {
val alpha by animateFloatAsState(
targetValue = if (visible) 1f else 0f,
label = "alpha"
)
Text(
"Hello",
modifier = Modifier.graphicsLayer { this.alpha = alpha }
)
}animateDpAsState
UI의 크기와 오프셋에는 Dp를 사용하므로 패딩, 크기 또는 위치를 애니메이션으로 변경할 때는 animateDpAsState를 사용하세요.
여기서는 전환할 때 상자의 크기가 80dp에서 160dp로 커집니다. 애니메이션되는 Dp를 size()에 전달하므로 상자의 크기가 부드럽게 조정됩니다.
@Composable
fun GrowingBox(big: Boolean) {
val size by animateDpAsState(
targetValue = if (big) 160.dp else 80.dp,
label = "size"
)
Box(
Modifier
.size(size)
.background(Color.Blue)
)
}animateColorAsState
색상에 애니메이션을 적용하려면 animateColorAsState를 사용하세요. 색상 공간을 따라 보간하므로 중간에 어색한 색조가 깜빡이는 대신 전환이 부드럽고 자연스럽게 보입니다.
여기서는 불리언 값에 따라 상태 표시 점이 빨간색과 초록색 사이에서 애니메이션됩니다.
@Composable
fun StatusDot(online: Boolean) {
val color by animateColorAsState(
targetValue = if (online) Color(0xFF4CAF50) else Color(0xFFF44336),
label = "status-color"
)
Box(
Modifier
.size(16.dp)
.clip(CircleShape)
.background(color)
)
}animationSpec으로 사용자 지정
기본적으로 이러한 도우미는 부드러운 스프링을 사용합니다. 타이밍을 제어하려면 animationSpec을 전달하세요. 고정된 지속 시간과 완화 곡선을 사용하려면 tween을 사용하세요.
이 패널은 부드럽게 가속한 후 감속하는 곡선을 사용해 400ms 동안 슬라이드됩니다.
@Composable
fun SlidingPanel(open: Boolean) {
val offset by animateDpAsState(
targetValue = if (open) 0.dp else 250.dp,
animationSpec = tween(
durationMillis = 400,
easing = FastOutSlowInEasing
),
label = "offset"
)
Box(Modifier.offset(x = offset)) { /* content */ }
}완화 곡선
완화는 애니메이션이 가속하고 감속하는 방식을 결정합니다. Compose에는 다음과 같은 여러 완화가 제공됩니다.
LinearEasing- 일정한 속도(기계적인 느낌)입니다.FastOutSlowInEasing- Material의 기본값으로, 빠르게 시작해 부드럽게 끝납니다.LinearOutSlowInEasing- 화면에 들어오는 요소에 사용합니다.FastOutLinearInEasing- 화면에서 나가는 요소에 사용합니다.
적절한 완화를 선택하면 움직임이 로봇처럼 보이지 않고 의도적으로 느껴집니다.
val progress by animateFloatAsState(
targetValue = if (done) 1f else 0f,
animationSpec = tween(500, easing = LinearOutSlowInEasing),
label = "progress"
)스프링 사양
고정된 지속 시간 대신 물리적이고 자연스럽게 느껴지는 스프링을 사용할 수 있습니다. 스프링은 dampingRatio(탄성 정도)와 stiffness(속도)로 정의됩니다.
스프링은 애니메이션 도중 목표가 변경되더라도 부드럽게 대응하므로 유용합니다.
val scale by animateFloatAsState(
targetValue = if (active) 1.2f else 1f,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
),
label = "scale"
)완료에 반응하기
값이 목표에 도달했을 때 콜백을 한 번 실행하는 것처럼, 애니메이션이 완료될 때 어떤 작업을 해야 하는 경우가 있습니다. animate*AsState는 바로 이런 용도로 finishedListener를 제공합니다.
val alpha by animateFloatAsState(
targetValue = if (gone) 0f else 1f,
label = "alpha",
finishedListener = { finalValue ->
if (finalValue == 0f) onFullyHidden()
}
)여러 속성 애니메이션
여러 animate*AsState 호출을 결합하면 둘 이상의 속성에 동시에 애니메이션을 적용할 수 있습니다. 각 호출은 자체 값을 추적하며, 함께 사용하면 더욱 풍부한 효과를 만들 수 있습니다.
여기서는 칩을 선택할 때 크기가 변하고 색상도 바뀝니다.
@Composable
fun SelectableChip(selected: Boolean, text: String) {
val scale by animateFloatAsState(if (selected) 1.1f else 1f, label = "s")
val bg by animateColorAsState(
if (selected) Color(0xFF3F51B5) else Color.LightGray,
label = "bg"
)
Box(
Modifier
.graphicsLayer { scaleX = scale; scaleY = scale }
.clip(RoundedCornerShape(16.dp))
.background(bg)
.padding(horizontal = 12.dp, vertical = 6.dp)
) { Text(text) }
}순수 Kotlin으로 스프링 구현하기
스프링이 실제로 무엇을 하는지 직관적으로 이해할 수 있도록 작은 순수 Kotlin 시뮬레이션을 살펴보겠습니다. 이 코드는 약간의 감쇠를 적용해 각 단계마다 값을 목표를 향해 조금씩 이동시킵니다. Compose의 스프링이 여러 프레임에 걸쳐 목표 값으로 수렴하는 방식과 비슷합니다.
fun main() {
var value = 0f
val target = 100f
var velocity = 0f
val stiffness = 0.1f
val damping = 0.6f
repeat(6) { step ->
val force = (target - value) * stiffness
velocity = (velocity + force) * damping
value += velocity
println("step $step -> ${"%.1f".format(value)}")
}
}Int와 Offset 애니메이션
이 계열은 실수와 색상에만 국한되지 않습니다. 배지 개수처럼 정수인 값에는 animateIntAsState를 사용하고, 2차원 위치를 한 번의 호출로 애니메이션하려면 animateOffsetAsState 또는 animateIntOffsetAsState를 사용하세요.
여기서는 IntOffset를 애니메이션해 칩이 대각선으로 이동합니다.
@Composable
fun SlidingChip(moved: Boolean) {
val pos by animateIntOffsetAsState(
targetValue = if (moved) IntOffset(120, 60) else IntOffset.Zero,
label = "pos"
)
Box(
Modifier
.offset { pos }
.size(40.dp)
.background(Color.Magenta)
)
}빠른 확인
불리언 값이 변경될 때 Dp로 측정된 상자의 너비를 부드럽게 애니메이션하려고 합니다. 어떤 API가 가장 적합할까요?
복습: animate*AsState
animate*AsState 계열은 단일 값에 애니메이션을 적용할 때 가장 먼저 선택하는 방법입니다.
- 타입에 맞는 변형을 선택하세요. 예:
animateFloatAsState,animateDpAsState,animateColorAsState등 targetValue를 설정하면 값이 변경될 때마다 결과가 해당 값으로 애니메이션됩니다.tween와 완화 또는spring을 사용해animationSpec으로 움직임을 조정하세요.- 여러 개를 결합해 여러 속성에 함께 애니메이션을 적용하세요.
- 애니메이션이 완료될 때 반응하려면
finishedListener를 사용하세요.
다음으로 AnimatedVisibility와 전환을 사용해 콘텐츠가 나타나고 사라지는 동작을 애니메이션으로 처리합니다.
자주 묻는 질문
“animate*AsState 기초” 강의는 무료인가요?
네 — “animate*AsState 기초” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Android Academy 강의 전체를 잠금 해제할 수 있습니다. Android Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“animate*AsState 기초”에서 뭘 배우나요?
단일 값을 부드럽게 애니메이션 처리합니다. 브라우저에서 직접 실행하는 실습 코드로 Android Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Android Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Android Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“animate*AsState 기초” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Android Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Android Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 애니메이션이 중요한 이유
- animate*AsState 기초
- AnimatedVisibility와 전환
- 제스처와 스프링 애니메이션