Property Animation은 Android 3.0(API 11)에서 도입된 Android의 애니메이션 시스템으로, 지정된 시간 동안 객체(View뿐만 아니라)의 실제 속성을 변경합니다. 기존의 View Animation과 달리 Property Animation은 객체의 실제 필드(좌표, 크기, 투명도, 색상)를 변경하며, 시각적 표시만 변경하지 않습니다. Google Android Developers(2026)에 따르면, 상위 100개 Android 앱의 89%에서 Property Animation이 사용됩니다. 다른 유형의 애니메이션에 대한 자세한 내용은 일반 애니메이션 가이드를 참조하세요.
주요 포인트
Property Animation은 Android SDK(android.animation 패키지)의 프레임워크로, 지정된 시간 내에 모든 객체(View, Drawable, 사용자 정의 클래스)의 모든 속성을 애니메이션합니다. View Animation이 View에서만 작동하고 시각적 표현(행렬 변환)만 변경하는 것과 달리, Property Animation은 객체의 실제 필드를 수정합니다. 즉, translationX 애니메이션 후 객체는 실제로 새 위치에 있으며 클릭은 새 위치에서 처리됩니다.
Property Animation 아키텍처는 세 가지 핵심 클래스를 기반으로 구축되었습니다: ValueAnimator — 기본 값 생성기, ObjectAnimator — 객체 속성에 바인딩하기 위한 하위 클래스, AnimatorSet — 그룹 애니메이션을 위한 오케스트레이터. 세 가지 모두 Interpolator(속도 곡선)와 TypeEvaluator(값 간 보간 규칙)를 지원합니다.
Android Performance Patterns(Google, 2025)에 따르면, Property Animation은 Interpolator가 올바르게 구성되고 onAnimationUpdate()에서 무거운 계산이 없을 때 최대 60FPS로 실행됩니다. 복잡한 애니메이션(3D, 물리)의 경우 Android 12+에서 RenderThread(RenderNode Animations)가 권장됩니다. Property Animation은 View 속성(translationX, rotationY, scaleX, alpha 등)을 애니메이션하는 주요 선택으로 남아 있습니다.
ObjectAnimator는 Property Animation에서 가장 인기 있는 클래스입니다. ValueAnimator를 확장하며 애니메이션 값으로 지정된 객체 속성의 setter를 자동으로 호출합니다. ObjectAnimator가 작동하려면 객체에 애니메이션할 속성에 대한 공개 setter가 있어야 합니다(예: “translationX” 속성의 setTranslationX(float)).
import android.animation.ObjectAnimator
import android.view.View
// ObjectAnimator for translationX
val animator = ObjectAnimator.ofFloat(
myView,
"translationX",
0f,
300f
).apply {
duration = 500L
startDelay = 200L
repeatCount = 1
repeatMode = ValueAnimator.REVERSE
interpolator = FastOutSlowInInterpolator()
start()
}
지원되는 View 속성: translationX, translationY, translationZ, rotation, rotationX, rotationY, scaleX, scaleY, alpha, x, y, elevation. ObjectAnimator.ofFloat()는 float 속성에, ofInt()는 int에, ofObject()는 사용자 정의 유형(색상, 점)에 사용됩니다. 색상 애니메이션의 경우 ArgbEvaluator 또는 HsvEvaluator와 함께 ofObject()를 사용하세요.
// ObjectAnimator와 사용자 정의 TypeEvaluator(색상)
import android.animation.ObjectAnimator
import android.animation.ArgbEvaluator
import android.graphics.Color
val colorAnim = ObjectAnimator.ofObject(
myView,
"backgroundColor",
ArgbEvaluator(),
Color.BLUE,
Color.RED
).apply {
duration = 1000L
repeatCount = ValueAnimator.INFINITE
repeatMode = ValueAnimator.REVERSE
start()
}
// 여러 속성을 동시에 애니메이션
val scaleXAnim = ObjectAnimator.ofFloat(myView, "scaleX", 1f, 1.5f)
val scaleYAnim = ObjectAnimator.ofFloat(myView, "scaleY", 1f, 1.5f)
val alphaAnim = ObjectAnimator.ofFloat(myView, "alpha", 1f, 0.5f)
AnimatorListener — 애니메이션 이벤트(onAnimationStart, onAnimationEnd, onAnimationCancel, onAnimationRepeat)를 추적하기 위한 인터페이스입니다. 필요한 메서드만 재정의하려면 AnimatorListenerAdapter를 사용하세요. Android 12부터 suspendAnimationFrame을 통한 코루틴 지원과 함께 Animator.AnimationCallback이 추가되었습니다.
ValueAnimator는 Property Animation의 기본 클래스로, 지정된 시간 동안 시작부터 끝까지 애니메이션 값을 생성합니다. ObjectAnimator와 달리 ValueAnimator는 객체에 바인딩되지 않습니다. 단순히 중간 값을 계산하고 리스너를 통해 알립니다. 개발자는 얻은 값으로 수행할 작업(View 속성 설정, Drawable 매개변수 변경, onDraw()에서 사용자 정의 그리기 업데이트 등)을 결정합니다.
import android.animation.ValueAnimator
import android.view.animation.LinearInterpolator
"> ValueAnimator: 로딩 진행 애니메이션
val valueAnimator = ValueAnimator.ofFloat(0f, 100f).apply {
duration = 2000L
interpolator = LinearInterpolator()
repeatCount = ValueAnimator.INFINITE
addUpdateListener { animator ->
val progress = animator.animatedValue as Float
progressBar.progress = progress.toInt()
progressText.text = "${progress.toInt()}%"
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationRepeat(animation: Animator) {
Log.d("Anim", "Progress animation restarted")
}
})
start()
}
ValueAnimator.ofInt() — 정수 속성(너비, 높이, 단계 수)에 사용됩니다. ValueAnimator.ofObject() — TypeEvaluator와 함께 사용자 정의 유형용입니다. ValueAnimator.ofPropertyValuesHolder() — 단일 타이머로 여러 속성을 병렬 애니메이션하여 각 속성에 대해 별도의 Animator를 사용하는 것보다 리소스를 절약합니다.
// ValueAnimator.ofObject와 PointEvaluator
import android.animation.ValueAnimator
import android.graphics.PointF
import android.animation.PointFEvaluator
val pointAnim = ValueAnimator.ofObject(
PointFEvaluator(),
PointF(0f, 0f),
PointF(300f, 500f)
).apply {
duration = 1000L
addUpdateListener { animator ->
val point = animator.animatedValue as PointF
movingView.x = point.x
movingView.y = point.y
}
start()
}
ValueAnimator 성능: 60FPS에서 onAnimationUpdate는 약 16.7ms마다 호출됩니다. 리스너 내에서 피해야 할 사항: 객체 할당(PointF/RectF는 한 번 생성), findViewById() 호출, 무거운 계산(파일 I/O, 네트워크). 20개 이상의 요소를 동시에 애니메이션하려면 20개의 개별 Animator 대신 하나의 Animator에서 PropertyValuesHolder를 사용하세요. 크기 변경 애니메이션의 경우 애니메이션 끝에서만 View.setLayoutParams()를 사용하세요(AnimatorListenerAdapter.onAnimationEnd를 통해).
AnimatorSet은 여러 Animator(ObjectAnimator, ValueAnimator) 인스턴스를 특정 순서로 실행할 수 있는 오케스트레이터입니다: 순차적(playSequentially), 병렬(playTogether), 지연 포함(after, before, with). AnimatorSet은 중첩을 지원합니다. 복잡한 시나리오의 경우 AnimatorSet에 다른 AnimatorSet이 포함될 수 있습니다.
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
// AnimatorSet: 순차 및 병렬 애니메이션
val fadeIn = ObjectAnimator.ofFloat(myView, "alpha", 0f, 1f)
val slideUp = ObjectAnimator.ofFloat(myView, "translationY", 100f, 0f)
val bounce = ObjectAnimator.ofFloat(myView, "scaleX", 1f, 1.1f, 1f)
val animatorSet = AnimatorSet().apply {
// 병렬: fadeIn + slideUp
play(fadeIn).with(slideUp)
"> 이후: 200ms 지연 bounce
play(bounce).after(200L)
duration = 400L
interpolator = FastOutSlowInInterpolator()
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
Log.d("Anim", "Set completed")
}
})
start()
}
AnimatorSet.Builder는 체인 구축을 위한 fluent API를 제공합니다: with() — 병렬, before() — 이전, after() — 이후. AnimatorSet은 세트의 모든 애니메이션을 중지하는 cancel()을 지원합니다. 복잡한 시나리오(25개 이상의 애니메이터)의 경우 PropertyValuesHolder를 사용하세요. 각 Animator에 대해 별도의 타이머를 사용하는 대신 단일 공유 타이머를 사용하므로 더 효율적입니다.
| Builder 메서드 | 설명 | 예제 |
|---|---|---|
| with(Animator) | 현재 애니메이션과 병렬 실행 | play(fadeIn).with(slideUp) |
| before(Animator) | 현재 애니메이션을 지정된 것보다 먼저 | play(fadeIn).before(bounce) |
| after(Animator) | 현재 애니메이션을 지정된 것보다 나중에 | play(bounce).after(slideUp) |
| after(Long) | 현재 애니메이션 전에 지연 | play(bounce).after(200L) |
Interpolator는 0에서 1까지 애니메이션의 속도 곡선을 정의합니다. Android는 내장 Interpolator를 제공합니다: LinearInterpolator(균일), AccelerateDecelerateInterpolator(느림-빠름-느림), FastOutSlowInInterpolator(Material Design), OvershootInterpolator(목표 초과), BounceInterpolator(바운스 포함), AnticipateOvershootInterpolator(시작 전 당김 및 목표 초과 포함). 사용자 정의 Interpolator는 TimeInterpolator를 통해 구현됩니다.
import android.animation.ObjectAnimator
import android.view.animation.BounceInterpolator
import android.view.animation.OvershootInterpolator
import android.view.animation.AnticipateOvershootInterpolator
// BounceInterpolator — 끝에서 바운스 효과
val bounceAnim = ObjectAnimator.ofFloat(myView, "translationY", 0f, -50f).apply {
duration = 600L
interpolator = BounceInterpolator()
start()
}
// AnticipateOvershoot — 당긴 후 초과
val anticipateAnim = ObjectAnimator.ofFloat(myView, "scaleX", 1f, 1.3f).apply {
duration = 500L
interpolator = AnticipateOvershootInterpolator(2.0f)
start()
}
TypeEvaluator — 시작과 끝 사이의 중간 값을 계산하는 evaluate(fraction, startValue, endValue) 메서드가 있는 인터페이스입니다. 내장: ArgbEvaluator(int 색상), FloatEvaluator, IntEvaluator, PointFEvaluator, RectEvaluator. 사용자 정의 데이터 유형(예: 세 개의 필드가 있는 사용자 정의 클래스 애니메이션)의 경우 자체 TypeEvaluator를 구현하세요. 동일한 설정으로 여러 View를 애니메이션하려면 PropertyValuesHolder를 사용하세요. 속성 이름과 해당 값의 배열을 허용합니다.
// ProgressState 클래스용 사용자 정의 TypeEvaluator
data class ProgressState(val progress: Float, val color: Int)
class ProgressEvaluator : TypeEvaluator<ProgressState> {
override fun evaluate(
fraction: Float,
startValue: ProgressState,
endValue: ProgressState
): ProgressState {
val progress = startValue.progress + fraction * (endValue.progress - startValue.progress)
val color = ArgbEvaluator().evaluate(
fraction, startValue.color, endValue.color
) as Int
return ProgressState(progress, color)
}
}
"> PropertyValuesHolder — 최대 성능
val pvh1 = PropertyValuesHolder.ofFloat("scaleX", 1f, 1.5f)
val pvh2 = PropertyValuesHolder.ofFloat("scaleY", 1f, 1.5f)
val pvhAnim = ObjectAnimator.ofPropertyValuesHolder(myView, pvh1, pvh2).apply {
duration = 300L
start()
}
자주 묻는 질문
View Animation(Tween Animation)은 행렬 변환을 통해 View의 시각적 표현만 변경하며 객체의 실제 속성에는 영향을 미치지 않습니다. View Animation에서 translationX 애니메이션 후 요소는 시각적으로 이동하지만 클릭은 원래 위치에서 계속 처리됩니다. Property Animation(ObjectAnimator)은 실제 속성을 변경하므로 애니메이션 후 요소가 물리적으로 새 위치에 있게 됩니다.
animator.cancel()을 호출하면 애니메이션이 즉시 중지되고 최종 값이 적용되지 않습니다. animator.end()를 호출하면 애니메이션이 최종 상태로 전환되고 중지됩니다. AnimatorSet의 경우 set.cancel()이 세트의 모든 애니메이션을 중지합니다. Animator.pause()와 resume()은 일시 중지를 위해 API 19+에서 사용할 수 있습니다.
Material Design 권장 사항: FastOutSlowInInterpolator — 요소 나타나기 및 사라지기 애니메이션, LinearInterpolator — 로딩 표시기, OvershootInterpolator — 강조 효과(버튼), BounceInterpolator — 당겨서 새로고침 및 스프링 요소. 화면 밖에서 나타나는 애니메이션의 경우 AccelerateDecelerateInterpolator를 사용하세요.
확인 사항: (1) 객체에 지정된 속성에 대한 공개 setter(setPropertyName())가 있는지, (2) 속성이 “set” 뒤에 소문자로 camelCase로 작성되었는지, (3) setter가 전달하는 유형과 동일한 유형을 허용하는지(ofFloat → setPropertyName(float)). View의 경우 모든 표준 속성(alpha, translationX, rotation 등)에 setter가 있습니다.
ObjectAnimator — 단일 표준 View 속성(alpha, translationX, rotation)을 애니메이션할 때. ValueAnimator — 하나의 리스너에서 여러 속성을 업데이트해야 하거나, 비View 속성(진행률, 사용자 정의 그리기)을 애니메이션해야 하거나, 객체에 필요한 속성에 대한 setter가 없을 때. ValueAnimator는 더 유연하지만 수동 업데이트에 더 많은 코드가 필요합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.