Animation in Android applications is not just an interface decoration, but a powerful tool for improving the user experience. Properly implemented effects help visualize interactions, make navigation more intuitive, and can even increase conversion in commercial projects. However, many developers are still limited to standard transitions fade-in/fade-out, without using the full potential of the platform.

In this article we will look 5 modern approaches to creating animations on Android - from basic XML declarations to advanced techniques using Jetpack Compose i Lottie. You'll learn how to integrate animation into an existing project without losing productivity, which tools to choose for different tasks, and where to look for ready-made solutions for common scenarios. We will pay special attention to optimization: even the most beautiful animation should not slow down the application on weak devices.

1. Basic animation via XML: where to start for a beginner

If you are just starting to work with animation in Android, start with declarative approach via XML files. This method has been supported since the first versions of the platform and is ideal for simple effects: the smooth appearance of elements, rotating buttons or changing colors. All animation files are stored in the folder res/anim/ and connected via Java/Kotlin code.

Main types of XML animations:

  • ๐Ÿ”„ Tween animation (<set>, <alpha>, <scale>): changes the properties of an object over time (for example, transparency or size).
  • ๐Ÿ“ Frame animation (<animation-list>): sequential display of frames (as in a GIF).
  • ๐ŸŽฏ Property Animation (via ObjectAnimator): more flexible control over the properties of objects.

Example of a simple tween animation for a button (file res/anim/fade_in.xml):

<set xmlns:android="http://schemas.android.com/apk/res/android"

android:duration="1000">

<alpha

android:fromAlpha="0.0"

android:toAlpha="1.0" />

</set>

To apply it to an element, use in code:

val animation = AnimationUtils.loadAnimation(this, R.anim.fade_in)

button.startAnimation(animation)

โš ๏ธ Attention: XML animations do not support dynamic changes of parameters at runtime. If you need to interrupt or modify the animation based on a condition, use ObjectAnimator.
๐Ÿ“Š What type of animation do you most often use in projects?
XML (tween/frame)
Property Animation (ObjectAnimator)
Lottie/After Effects
Jetpack Compose
Haven't tried it yet

2. Property Animation: flexibility and control

For more complex scenarios where required dynamic control animation (for example, reaction to user gestures), suitable Property Animation API. Unlike XML, here you work directly with object properties through classes ObjectAnimator, ValueAnimator and AnimatorSet.

Main advantages:

  • ๐Ÿ”ง Interpolators: setting acceleration/deceleration curves (AccelerateDecelerateInterpolator, BounceInterpolator).
  • ๐Ÿ“ฑ Cancel and pause: the ability to pause or cancel the animation at any time.
  • ๐Ÿ”„ Animation chains: sequential or parallel execution via AnimatorSet.

An example of animation for moving a view across the screen with acceleration:

val view = findViewById<View>(R.id.target_view)

val animator = ObjectAnimator.ofFloat(view, "translationX", 0f, 300f).apply {

duration = 1500

interpolator = AccelerateInterpolator(1.5f)

}

animator.start()

To create a chain of animations (for example, first scaling, then rotation):

val scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 2f)

val rotate = ObjectAnimator.ofFloat(view, "rotation", 0f, 180f)

AnimatorSet().apply {

play(scaleX).before(rotate) // first scale, then rotation

start()

}

๐Ÿ’ก

Use ViewPropertyAnimator to simultaneously change several properties of the same type - this optimizes performance by reducing the number of calls invalidate().

3. Lottie: lossless animation from After Effects

If you need complex vector animations (for example, loading screens, morphing illustrations or characters), but do not have time to draw them manually, use Lottie โ€”a library from Airbnbthat renders animations from Adobe After Effects real time.

How it works:

  1. The designer creates the animation in After Effects and exports it to format .json via a plugin Bodymovin.
  2. You add a file to the project (folder assets/) and connect the dependency com.airbnb.android:lottie.
  3. In the markup, add <com.airbnb.lottie.LottieAnimationView> and load the animation.

Integration example:

<com.airbnb.lottie.LottieAnimationView

android:id="@+id/animationView"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

app:lottie_rawRes="@raw/loading_animation"

app:lottie_loop="true"

app:lottie_autoPlay="true"/>

You can control playback in the code:

val animationView = findViewById<LottieAnimationView>(R.id.animationView)

animationView.playAnimation() // start

animationView.pauseAnimation() // pause

animationView.speed = 2f // acceleration by 2 times

Parameter Lottie Description Default value
lottie_rawRes JSON file resource ID โ€”
lottie_loop Animation looping false
lottie_autoPlay Automatic start false
lottie_speed Playback speed 1.0
โš ๏ธ Attention: Lottie animations can significantly increase the size of the APK. Optimize JSON files using the tool LottieFiles Optimizer (remove unnecessary layers and reduce the number of key frames).
Where to download ready-made Lottie animations?

Free animations can be found at resources:

- LottieFiles (more than 100,000 files)

- Lordicon (icons with animation)

- Icons8 (simple animations for UI).

Pay attention to the license - some files require attribution.

4. MotionLayout: complex transitions without code

MotionLayout is an extension ConstraintLayoutthat allows you to create between interface states directly in XML, without writing Java/Kotlin code. The tool is ideal for: complex transition animations between interface states directly in XML, without writing Java/Kotlin code. The tool is ideal for:

  • ๐Ÿ“ฑ Adaptive interfaces: smooth changes in the arrangement of elements when the screen is rotated.
  • ๐Ÿ”„ Complex transitions: for example, opening a panel while simultaneously moving other elements.
  • ๐ŸŽฏ Animations with gestures: reaction to swipes or clicks.

Main components MotionLayout:

  • <ConstraintSet> โ€”describes the state of elements at the beginning and end of the animation.
  • <Transition> โ€” defines the transition parameters (duration, interpolator).
  • app:motionScene โ€” link to a file with a description of the animation (res/xml/scene_*.xml).

Example of a simple transition (file res/xml/scene_main.xml):

<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto">

<ConstraintSet android:id="@+id/start">

<Constraint android:id="@id/button" ... />

</ConstraintSet>

<ConstraintSet android:id="@+id/end">

<Constraint android:id="@id/button"

app:layout_constraintTop_toTopOf="parent"

app:layout_constraintStart_toStartOf="parent"/>

</ConstraintSet>

<Transition

app:constraintSetStart="@id/start"

app:constraintSetEnd="@id/end"

app:duration="1000"/>

</MotionScene>

In the markup we connect MotionLayout:

<androidx.constraintlayout.motion.widget.MotionLayout

android:layout_width="match_parent"

android:layout_height="match_parent"

app:layoutDescription="@xml/scene_main">

<Button android:id="@+id/button" ... />

</MotionLayout>

To start the transition by click:

val motionLayout = findViewById<MotionLayout>(R.id.motionLayout)

button.setOnClickListener {

motionLayout.transitionToEnd() // transition to the final state

}

Add dependency implementation "androidx.constraintlayout:constraintlayout:2.1.4"

Create a scene file in res/xml/

Describe the initial and final states in <ConstraintSet>

Connect app:layoutDescription in markup

Check animation in Android Studio Layout Editor-->

5. Jetpack Compose: a modern approach to animation

If you are developing a new project or migrating to Jetpack Compose, then for animation you should use the built-in tools of this framework. Compose offers declarative approach, where animation is described as a state of the UI, which simplifies management and testing.

Main APIs for animation in Compose:

  • ๐Ÿ”„ animate*AsState (animateFloatAsState, animateDpAsState): smooth change of value (for example, alpha channel or size).
  • ๐ŸŽฏ updateTransition: control several animations at the same time.
  • ๐Ÿ“ฑ AnimatedVisibility: appearance/disappearance of elements with effects.
  • ๐Ÿ”ง rememberInfiniteTransition: looping animations (for example, button pulsation).

An example of an animation for changing the size of a button when pressed:

var expanded by remember { mutableStateOf(false) }

val scale by animateFloatAsState(

targetValue = if (expanded) 1.2f else 1f,

animationSpec = spring(dampingRatio = 0.5f)

)

Button(

onClick = { expanded = !expanded },

modifier = Modifier.scale(scale)

) {

Text("Press me")

}

For complex transitions, use updateTransition:

val transition = updateTransition(expanded, label = "transitionExample")

val rectColor by transition.animateColor(label = "colorTransition") { isExpanded ->

if (isExpanded) Color.Green else Color.Red

}

val borderWidth by transition.animateDp(label = "borderTransition") { isExpanded ->

if (isExpanded) 10.dp else 2.dp

}

Box(

Modifier

.background(rectColor)

.border(borderWidth, Color.Black)

.clickable { expanded = !expanded }

)

โš ๏ธ Attention: In Compose, animations are automatically interrupted when the composition leaves the composition (for example, when the screen is rotated). To save the state, use rememberSaveable.
๐Ÿ’ก

Jetpack Compose allows you to describe animations as part of the UI state, which simplifies synchronization with data and reduces the number of bugs associated with state mismatches.

6. Optimization of animations: how not to slow down the application

Even the most beautiful animation will lose its meaning if there is slow down the interface. To avoid performance problems, follow these rules:

Problems and solutions:

Problem Cause Solution
Animation lags Too frequent calls invalidate() Use ViewPropertyAnimator or ObjectAnimator instead ValueAnimator.
High CPU consumption Complex calculations in onDraw() Move logic to ValueAnimator or use Lottie for vector animations.
Jerky animation Low FPS (less than 60) Reduce the number of animated properties or use Interpolator for smoothing.
Memory leaks Unreleased animation resources Always call animator.cancel() to onCleared() or onDestroy().

Diagnostic tools:

  • ๐Ÿ” Android Profiler: monitor FPS and CPU usage during animation.
  • ๐Ÿ“Š Layout Inspector: check view hierarchy - deep nesting can slow down rendering.
  • ๐Ÿ› ๏ธ Overdraw Debugging: enable in the developer settings to find unnecessary redraws.

Critical error: animations on the main thread block the UI. Always use ValueAnimator or ObjectAnimatorwhich automatically optimize execution on the Android animation framework.

7. Ready-made solutions: libraries and tools

You donโ€™t always need to reinvent the wheel. For typical tasks, you can use ready-made libraries that will save time and guarantee stability:

Popular libraries for animations:

  • ๐ŸŽฌ Lottie (already mentioned): for vector animations from After Effects.
  • ๐Ÿ”„ Rebound (from Facebook): implementation of physically correct animations (springs, bounces).
  • ๐Ÿ“ฑ AndroidViewAnimations: a collection of ready-made effects (shake, ripple, rotation).
  • ๐ŸŽฏ Shimmer: flickering animation for loading screens ("skeleton" effect).
  • ๐Ÿ”ง TransitionEverywhere: backported transitions from new APIs for older versions of Android.

Example of use Shimmer for the loading effect:

<com.facebook.shimmer.ShimmerFrameLayout

android:id="@+id/shimmerLayout"

android:layout_width="match_parent"

android:layout_height="wrap_content"

app:shimmer_autostart="true">

<include layout="@layout/placeholder_skeleton"/>

</com.facebook.shimmer.ShimmerFrameLayout>

In the code:

val shimmerLayout = findViewById<ShimmerFrameLayout>(R.id.shimmerLayout)

shimmerLayout.startShimmer() // start animation

// shimmerLayout.stopShimmer() - stop

โš ๏ธ Attention: Before using third-party libraries, check their relevance. Some projects (for example, NineOldAndroids) are outdated and replaced by native solutions in modern APIs.

FAQ: Frequently asked questions about animations on Android

Is it possible to make animation without XML, only through code?

Yes, all types of animations (except MotionLayout) can be created programmatically. For example, instead of the XML file for ObjectAnimator you can write:

ObjectAnimator.ofFloat(view, "alpha", 0f, 1f).apply {

duration = 1000

start()

}

This is convenient if the animation parameters depend on runtime conditions (for example, data from the server).

How to make animation by swipe (like in Tinder)?

For animation by gestures, use a combination of GestureDetector and ObjectAnimator. Example:

  1. Track the movement of your finger in onTouchEvent.
  2. Update the position of the view through view.x = newX.
  3. At the end of the gesture, start a return or delete animation:
val animator = ObjectAnimator.ofFloat(view, "x", view.x, if (swipeRight) 1000f else -1000f)

animator.interpolator = AccelerateInterpolator()

animator.addListener(object : AnimatorListenerAdapter() {

override fun onAnimationEnd(animation: Animator) {

view.visibility = View.GONE // deletion after animation

}

})

animator.start()

Why does animation slow down on older devices?

On devices with Android 5.0 and below, problems may arise due to:

  • Lack of hardware acceleration for some operations.
  • Outdated renderer Canvas.
  • Unoptimized libraries (for example, old versions) Lottie).

Solutions:

  • Disable unnecessary effects for old APIs via Build.VERSION.SDK_INT.
  • Use hardwareAccelerated="true" in the manifest.
  • Replace complex animations with simple ones (for example, instead of Lottie โ€” GIF).
How to test animation on different devices?

Use Android Emulator with different configurations:

  1. Create virtual devices with different versions of Android (from 5.0 to 14).
  2. Enable the option Show layout bounds in the developer settings to check the boundaries of elements.
  3. Run adb shell dumpsys gfxinfo <package> to analyze FPS.

For automated testing, use Espresso s IdlingResource to wait for the end of animations.

Where to find inspiration for animations?

Explore these resources: