Table of Contents
From View Animations to Property Animations
View animations change how a view looks over time, but they do not actually change its underlying properties. With property animations, you animate real values on real objects. This means the object actually moves, fades, or scales in a way that the system and your code can query and rely on.
Property animations are based on the android.animation package and the core classes such as ValueAnimator, ObjectAnimator, and AnimatorSet. They work on any object, not just views, as long as there is a way to read and write the property you want to animate.
ValueAnimator: Animating Raw Values
ValueAnimator is the foundation of the property animation system. It does not know anything about views or properties. It simply generates values over time and calls you back on every animation frame.
You create a ValueAnimator with a range of values, usually using ofInt or ofFloat, then listen for changes and apply the animated value yourself.
val animator = ValueAnimator.ofFloat(0f, 1f)
animator.duration = 1000L
animator.addUpdateListener { valueAnimator ->
val value = valueAnimator.animatedValue as Float
// Use `value` to update something, for example alpha, position, or a number in the UI
view.alpha = value
}
animator.start()
The important part is addUpdateListener. Inside the listener you read animatedValue and apply it. This gives you full control. You can animate non visual things as well, such as a number used in your game logic, or a progress percentage.
ValueAnimator does not modify any property by itself. It only computes intermediate values. You must apply those values manually inside the update listener.
You can also control other details like delay, repeat count, and repeat mode.
animator.startDelay = 500L
animator.repeatCount = 2
animator.repeatMode = ValueAnimator.REVERSEThis starts after half a second, runs forward, reverses, and repeats twice.
ObjectAnimator: Animating a Property Automatically
ObjectAnimator is built on top of ValueAnimator. Instead of giving you raw values only, it reads and writes a specific property on a target object for you.
To use ObjectAnimator, you need:
- A target object, usually a view such as
view. - A property name as a string, such as
"alpha"or"translationX". - One or more values to animate between.
val fadeOut = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)
fadeOut.duration = 300L
fadeOut.start()
This animation modifies view.alpha directly over 300 milliseconds. Under the hood, ObjectAnimator uses reflection to find setAlpha(float) and getAlpha() on the view.
Common built in properties for views include alpha, translationX, translationY, rotation, rotationX, rotationY, scaleX, scaleY, x, y, and backgroundColor with the appropriate type.
Animating colors uses ofArgb and usually requires a color evaluator.
val colorAnim = ObjectAnimator.ofArgb(
view,
"backgroundColor",
Color.RED,
Color.BLUE
)
colorAnim.duration = 1000L
colorAnim.start()
ObjectAnimator requires a readable and writable property. In practice this means there must be a getPropertyName and setPropertyName pair, for example getAlpha and setAlpha. Without these functions, ObjectAnimator cannot work for that property.
You can define your own properties on custom classes by following this naming convention, then animate them with ObjectAnimator.
AnimatorSet: Combining Animations
Often you need multiple property animations working together, for example move a view while fading it out. AnimatorSet groups several Animator objects and controls them as one unit.
You can play animations together or one after another.
val moveRight = ObjectAnimator.ofFloat(view, "translationX", 0f, 300f)
val fadeOut = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)
val set = AnimatorSet()
set.playTogether(moveRight, fadeOut)
set.duration = 500L
set.start()This moves the view to the right and fades it out at the same time.
To run them sequentially:
val moveRight = ObjectAnimator.ofFloat(view, "translationX", 0f, 300f)
val fadeOut = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)
val set = AnimatorSet()
set.playSequentially(moveRight, fadeOut)
set.start()
You can also link animations with play().with(), before(), and after() to express more complex timing.
Interpolators: Controlling Animation Pace
An interpolator controls how time is mapped to animation progress. Property animations support the same interpolator concept that you use in other animations.
For example, if you want an animation to start slowly and then speed up, you can use AccelerateInterpolator. If you want a bounce effect at the end, you can use BounceInterpolator.
val moveUp = ObjectAnimator.ofFloat(view, "translationY", 500f, 0f)
moveUp.duration = 600L
moveUp.interpolator = BounceInterpolator()
moveUp.start()The interpolator does not change the duration, but it changes how fast or slow the property value appears to change over time inside that duration.
Evaluators: Custom Value Calculation
For some types of values, such as integers, floats, and colors, Android has built in evaluators that know how to compute intermediate values. When you animate more complex types, you can provide a custom evaluator.
A TypeEvaluator<T> accepts a fraction between 0 and 1 and two values, a start and an end, and returns the interpolated value of type T.
class PointEvaluator : TypeEvaluator<PointF> {
override fun evaluate(
fraction: Float,
startValue: PointF,
endValue: PointF
): PointF {
val x = startValue.x + (endValue.x - startValue.x) * fraction
val y = startValue.y + (endValue.y - startValue.y) * fraction
return PointF(x, y)
}
}
You can then use this evaluator with ValueAnimator.ofObject or ObjectAnimator.ofObject.
val start = PointF(0f, 0f)
val end = PointF(300f, 300f)
val animator = ValueAnimator.ofObject(PointEvaluator(), start, end)
animator.duration = 1000L
animator.addUpdateListener { valueAnimator ->
val point = valueAnimator.animatedValue as PointF
view.x = point.x
view.y = point.y
}
animator.start()This lets you animate along custom paths or between complex states that are not just numbers.
Listening to Animation Events
Property animations expose lifecycle callbacks so you can react to the start, end, repeat, or cancel of an animation.
You can add an AnimatorListenerAdapter to any Animator such as ObjectAnimator or AnimatorSet.
fadeOut.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator) {
// Prepare view or state
}
override fun onAnimationEnd(animation: Animator) {
view.visibility = View.GONE
}
})This is useful when you need to remove views after finishing an animation, update state, or start another process after the motion finishes.
Animating with ViewPropertyAnimator
ViewPropertyAnimator is a convenience API attached directly to views. It is built on property animations but offers a fluent syntax and handles some details for you.
You can access it calling view.animate() and chain property calls.
view.animate()
.alpha(0f)
.translationY(100f)
.setDuration(300L)
.withEndAction {
view.visibility = View.GONE
}
This is less flexible than ObjectAnimator in some advanced cases, but for common view animations it is concise and efficient.
Performance and Best Practices
Property animations run on the UI thread by default. Animating certain properties can cause more work for the rendering system. For smoother animations, prefer properties that do not force a full layout pass.
Properties such as alpha, translationX, translationY, scaleX, and scaleY are generally safe, because they mainly affect how the view is drawn rather than how it is measured and laid out.
Avoid constantly changing layout related properties during animations if possible. For example, repeatedly changing layout parameters that trigger a re layout can cause stutters.
Prefer animating properties that the GPU can handle efficiently, such as alpha and translationX or translationY. Avoid heavy layout recalculations inside animation update listeners.
When animating many views at once or creating long running animations, be aware of memory pressure. Avoid creating new objects inside onAnimationUpdate on every frame. Reuse objects when possible.
Property Animations Beyond Views
Although property animations are heavily used with views, they work with any object that exposes properties with appropriate getters and setters. For example, you can animate the radius of a custom shape, the progress of a non standard progress bar, or variables inside a game engine.
By separating the concept of "value over time" from "what the value controls", property animations give you a flexible tool for both visual effects and non visual state changes.