Lottie is the go-to library for After Effects animations in Android apps. It renders animations natively using the Android Canvas and RenderThread â no WebView, no GIF overhead. This guide covers setup, playback control, and integration with both classic Views and Jetpack Compose.
Why Lottie for Android?
- Native rendering via Android's Canvas â not a WebView
- Smooth at 60fps even on mid-range devices
- Small files â complex animations are often under 50KB
- Programmatic control â play, pause, loop, seek, change speed
-
Jetpack Compose support via the official
lottie-composemodule
Step 0: Preview Before You Build
Before adding any Lottie file to your Android project, check it in IconKing:
- Preview the animation exactly as it will render
- Edit colors to match your Material 3 design system
- Convert
.jsonâ.lottieformat for 75% smaller file size - Catch broken layers or After Effects effects that don't render on Android
Free, no account required. Drop the file, preview, adjust, download.
Step 1: Add the Dependency
In build.gradle.kts (app module):
dependencies {
implementation("com.airbnb.android:lottie:6.4.0") // for Views
// or
implementation("com.airbnb.android:lottie-compose:6.4.0") // for Jetpack Compose
}
Sync your project.
Step 2: Add Your Animation File
Place your .json or .lottie file in app/src/main/res/raw/:
app/
src/
main/
res/
raw/
loading.json
success.lottie
Step 3: Basic Usage (XML/Views)
In your layout XML:
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/animationView"
android:layout_width="200dp"
android:layout_height="200dp"
app:lottie_rawRes="@raw/loading"
app:lottie_autoPlay="true"
app:lottie_loop="true" />
That's it for a looping animation. lottie_rawRes points to your file in res/raw/.
Step 4: Controlling Playback in Kotlin
val animationView = binding.animationView
// Play
animationView.playAnimation()
// Pause
animationView.pauseAnimation()
// Stop and reset
animationView.cancelAnimation()
animationView.progress = 0f
// Play with a completion listener
animationView.addAnimatorListener(object : Animator.AnimatorListener {
override fun onAnimationEnd(animation: Animator) {
// Handle completion
}
// ... other overrides
})
Loop Modes
// Loop forever
animationView.repeatCount = LottieDrawable.INFINITE
// Play once
animationView.repeatCount = 0
// Play 3 times
animationView.repeatCount = 2 // 0-based repeat count
// Reverse after each cycle
animationView.repeatMode = LottieDrawable.REVERSE
Speed Control
// Half speed
animationView.speed = 0.5f
// Double speed
animationView.speed = 2.0f
// Reverse playback
animationView.speed = -1.0f
Seek to a Specific Frame or Progress
// Jump to normalized progress (0f to 1f)
animationView.progress = 0.5f
// Play from frame 0 to frame 60
animationView.setMinAndMaxFrame(0, 60)
animationView.playAnimation()
Dynamic Color Replacement
Override colors at runtime â useful for theming or dark mode:
val colorFilter = SimpleColorFilter(Color.RED)
val keyPath = KeyPath("**", "Fill 1")
animationView.addValueCallback(keyPath, LottieProperty.COLOR_FILTER) { colorFilter }
The keypath uses the After Effects layer structure. Open your .json file and look for the layer/shape names, or use IconKing to browse the layer structure before writing code.
Jetpack Compose
// build.gradle.kts
implementation("com.airbnb.android:lottie-compose:6.4.0")
import com.airbnb.lottie.compose.*
@Composable
fun LoadingAnimation() {
val composition by rememberLottieComposition(
LottieCompositionSpec.RawRes(R.raw.loading)
)
val progress by animateLottieCompositionAsState(
composition,
iterations = LottieConstants.IterateForever
)
LottieAnimation(
composition = composition,
progress = { progress },
modifier = Modifier.size(200.dp)
)
}
One-shot animation with Compose
@Composable
fun SuccessAnimation(onComplete: () -> Unit) {
val composition by rememberLottieComposition(
LottieCompositionSpec.RawRes(R.raw.success)
)
val progress by animateLottieCompositionAsState(
composition,
iterations = 1
)
// Detect when animation finishes
LaunchedEffect(progress) {
if (progress == 1f) onComplete()
}
LottieAnimation(
composition = composition,
progress = { progress },
modifier = Modifier.size(150.dp)
)
}
Using dotLottie (.lottie) Format
dotLottie files are ~75% smaller. Lottie 6.x supports them natively:
<!-- In XML layout -->
<com.airbnb.lottie.LottieAnimationView
app:lottie_rawRes="@raw/success_lottie" <!-- success.lottie in res/raw/ -->
app:lottie_autoPlay="true"
app:lottie_loop="false" />
// In code
animationView.setAnimation(R.raw.success_lottie)
The library detects the format automatically. To convert your .json to .lottie, use IconKing.
Loading from a URL
animationView.setAnimationFromUrl("https://example.com/animation.json")
animationView.playAnimation()
For caching, Lottie handles this automatically based on the URL. For production, cache the file locally to avoid network failures.
Performance Tips
1. Stop animations when the view goes off-screen
override fun onPause() {
super.onPause()
animationView.pauseAnimation()
}
override fun onResume() {
super.onResume()
animationView.resumeAnimation()
}
2. Use .lottie format
75% smaller files = faster load time and smaller APK size. Convert at IconKing.
3. Enable hardware acceleration for complex animations
animationView.enableMergePathsForKitKatAndAbove(true)
4. Avoid playing multiple animations simultaneously
Each running LottieAnimationView consumes CPU/GPU. Pause off-screen animations, especially in RecyclerView.
Complete Example: Splash Screen
class SplashActivity : AppCompatActivity() {
private lateinit var binding: ActivitySplashBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySplashBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.splashAnimation.apply {
setAnimation(R.raw.splash)
repeatCount = 0
speed = 1.0f
addAnimatorListener(object : Animator.AnimatorListener {
override fun onAnimationEnd(animation: Animator) {
navigateToMain()
}
override fun onAnimationStart(animation: Animator) {}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(animation: Animator) {}
})
playAnimation()
}
}
private fun navigateToMain() {
startActivity(Intent(this, MainActivity::class.java))
finish()
}
}
Common Issues
Animation not showing
- Confirm the file is in
res/raw/(notres/drawable/) - Confirm
playAnimation()is called orlottie_autoPlay="true"is set in XML
Animation plays too fast or too slow
Check the speed property. The default is 1.0f. Also make sure you haven't accidentally set repeatMode without a proper repeatCount.
Colors look wrong on device
Preview in IconKing first. If it looks correct there, the issue may be device-specific rendering. Use addValueCallback with a ColorFilter to override the color at runtime.
Different rendering on Android vs. iOS
Some After Effects effects (Gaussian blur, path trim) render differently on Android vs. iOS. Check the specific effect's support in the lottie-android documentation.
Finding Lottie Files for Android
Good sources:
- LottieFiles â the largest Lottie library
- IconKing â preview files before adding them to your project, edit colors to match Material 3, convert between formats
Before adding any file: open it in IconKing to verify the animation looks correct, matches your app's color scheme, and doesn't have any broken layers. Five minutes of preview saves 30 minutes of debugging in Android Studio.
Summary
- Add
lottie:6.4.0(Views) orlottie-compose:6.4.0(Compose) to your dependencies - Put your
.jsonor.lottiefile inres/raw/ - Use
LottieAnimationViewin XML orLottieAnimationin Compose - Control playback with
playAnimation(),speed,repeatCount - Use
addValueCallbackfor dynamic color overrides - Convert to
.lottieat IconKing for smaller APK size - Stop animations when views go off-screen
Top comments (0)