Androidx splashscreen compose
Drop-in animated splash screens for Android. Uses Jetpack Compose + AndroidX SplashScreen for smooth brand experiences without platform fights.
Let's cut to the chase: Android's default splash screen is boring. This library lets you create stunning animated splash screens using Compose without the headache. No more static drawables, no more janky transitions. The project is written primarily in Kotlin, distributed under the Apache License 2.0 license, first published in 2025. Key topics include: android, animation, branding, jetpack-compose, mobile-development.
androidx-splashscreen-compose ๐จ
Let's cut to the chase: Android's default splash screen is boring. This library lets you create stunning animated splash screens using Compose without the headache. No more static drawables, no more janky transitions.
What's the Point? ๐ฏ
Look, we all know the pain points:
- Android's splash screen is just a static image
- Animations? Good luck with that
- Transitions that look like they're from 2010
- Zero Compose support out of the box
Here's what you get with androidx-splashscreen-compose:
- Drop-in Compose animations that actually look good
- Smooth transitions that don't make users cringe
- Complete control over timing and animations
- Works with AndroidX SplashScreen, not against it
Get Started in 30 Seconds ๐
- Add the dependency:
groovyimplementation 'net.kibotu:androidx-splashscreen-compose:{latest-version}'
- Create your splash screen:
kotlinclass MainActivity : ComponentActivity() { private var splashScreen: SplashScreenDecorator? = null override fun onCreate(savedInstanceState: Bundle?) { val exitDuration = 800L // Initialize before super.onCreate() splashScreen = splash { exitAnimationDuration = exitDuration composeViewFadeDurationOffset = 200 backgroundColor = Color.White // match your windowSplashScreenBackground content { MyAnimation( isVisible = isVisible.value, exitAnimationDuration = exitDuration.milliseconds, onStartExitAnimation = { startExitAnimation() } ) } } splashScreen?.shouldKeepOnScreen = false super.onCreate(savedInstanceState) setContent { MyAppTheme { MainScreen() } } // Dismiss after your content is ready, e.g. after requests are complete lifecycleScope.launch { delay(2.seconds) splashScreen?.dismiss() } } override fun onDestroy() { splashScreen = null super.onDestroy() } }
That's it. No, really.
Show Me the Good Stuff ๐จ
Heartbeat Animation Example
Here's a real-world example of a heartbeat animation that actually ships in production apps:
kotlinfun HeartBeatAnimation( modifier: Modifier = Modifier, isVisible: Boolean = true, exitAnimationDuration: Duration = Duration.ZERO, onStartExitAnimation: () -> Unit = {} ) { // Animation constants val rippleCount = 4 val rippleDurationMs = 3313 val rippleDelayMs = rippleDurationMs / 8 val baseSize = 144.dp val containerSize = 288.dp // Track exit animation state var isExitAnimationStarted by remember { mutableStateOf(false) } // Trigger exit animation when visibility changes LaunchedEffect(isVisible) { if (!isVisible && !isExitAnimationStarted) { isExitAnimationStarted = true onStartExitAnimation() } } // Calculate screen diagonal for exit animation scaling val configuration = LocalConfiguration.current val screenWidth = configuration.screenWidthDp val screenHeight = configuration.screenHeightDp val screenDiagonal = sqrt((screenWidth * screenWidth + screenHeight * screenHeight).toFloat()) // Exit animation scale with snappy easing val snappyEasing = CubicBezierEasing(0.2f, 0.0f, 0.2f, 1.0f) val exitAnimationScale by animateFloatAsState( targetValue = if (isExitAnimationStarted) screenDiagonal / baseSize.value else 0f, animationSpec = tween( durationMillis = exitAnimationDuration.toInt(DurationUnit.MILLISECONDS), easing = snappyEasing ), label = "exitScale" ) // Infinite ripple animation transition val infiniteTransition = rememberInfiniteTransition(label = "heartbeatTransition") Box( modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { // Only show ripples when visible and not exiting if (isVisible && !isExitAnimationStarted) { Box( modifier = Modifier.size(containerSize), contentAlignment = Alignment.Center ) { // Create ripple circles with staggered animations repeat(rippleCount) { index -> RippleCircle( infiniteTransition = infiniteTransition, index = index, rippleDurationMs = rippleDurationMs, rippleDelayMs = rippleDelayMs, baseSize = baseSize ) } } } // Exit animation circle if (isExitAnimationStarted) { Box( modifier = Modifier .size(baseSize) .graphicsLayer { scaleX = exitAnimationScale scaleY = exitAnimationScale } .background( color = blueCatalina, shape = CircleShape ) ) } } } @Composable private fun RippleCircle( infiniteTransition: InfiniteTransition, index: Int, rippleDurationMs: Int, rippleDelayMs: Int, baseSize: Dp ) { val totalDuration = rippleDurationMs + (rippleDelayMs * index) val easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f) // Animate scale from 1f to 4f val animatedScale by infiniteTransition.animateFloat( initialValue = 1f, targetValue = 4f, animationSpec = infiniteRepeatable( animation = tween( durationMillis = totalDuration, delayMillis = rippleDelayMs * index, easing = easing ), repeatMode = RepeatMode.Restart ), label = "rippleScale$index" ) // Animate alpha from 0.25f to 0f val animatedAlpha by infiniteTransition.animateFloat( initialValue = 0.25f, targetValue = 0f, animationSpec = infiniteRepeatable( animation = tween( durationMillis = totalDuration, delayMillis = rippleDelayMs * index, easing = easing ), repeatMode = RepeatMode.Restart ), label = "rippleAlpha$index" ) Box( modifier = Modifier .size(baseSize) .graphicsLayer { scaleX = animatedScale scaleY = animatedScale alpha = animatedAlpha } .background( color = blueCatalina, shape = CircleShape ) ) }
Pro Tips ๐ก
-
Timing is Everything
kotlinsplashScreen = splash { exitAnimationDuration = 800L // Sweet spot for most animations composeViewFadeDurationOffset = 200 // Prevents jarring transitions backgroundColor = splashBg // Match windowSplashScreenBackground content { // Your composable here } } -
Memory Management
kotlinoverride fun onDestroy() { splashScreen = null // Don't leak memory super.onDestroy() } -
Performance First
- Use
rememberInfiniteTransition()for repeating animations - Keep animations under 1 second (users hate waiting)
- Test on low-end devices
- Use
Comparison with Alternatives ๐
vs only AndroidX SplashScreen
| Feature | androidx-splashscreen-compose | AndroidX SplashScreen |
|---|---|---|
| Animation Support | โ Full Compose animations | โ Static vector only |
| Custom Content | โ Any Composable | โ Icon + background only |
| Transition Control | โ Precise timing control | โ Limited control |
| Branding Flexibility | โ Complete creative freedom | โ Very constrained |
| Implementation Complexity | โ Simple DSL setup | โ Minimal setup |
| Performance | โ Optimized Compose rendering | โ Lightweight |
| Backward Compatibility | โ Built on AndroidX | โ Native support |
vs Custom Splash Activities
| Feature | androidx-splashscreen-compose | Custom Splash Activity |
|---|---|---|
| Android 12+ Compliance | โ Fully compliant | โ Requires extra work |
| App Launch Performance | โ No additional activity | โ Extra activity overhead |
| Transition Seamlessness | โ Native system integration | โ Potential flicker |
| Code Complexity | โ Single file setup | โ Multiple components |
| Maintenance | โ Library handles updates | โ Manual Android compliance |
When to Use What ๐ค
Use androidx-splashscreen-compose when:
- You need animations that don't look like they're from a 2010 tutorial
- Your brand guidelines require more than a static logo
- You want Compose-based animations without the setup headache
- Android 12+ compliance with zero additional effort
- Seamless integration with existing AndroidX SplashScreen setup
Stick with AndroidX SplashScreen when:
- A static logo is all you need
- You're optimizing for the smallest possible APK size
- You don't need any custom animations
Choose Custom Splash Activity when:
- Pre-Android 12 apps with no compliance requirements
- Complex initialization flows requiring multiple screens
- Non-Compose apps with View-based animations
Compatibility ๐ฑ
- Minimum Android SDK: 23
- Target Android SDK: 36
- Kotlin: 2.3.0
- Java: 17
- Gradle: 9.4.0
Contributing ๐ค
Got ideas? Found a bug? PRs are welcome:
- Fork it
- Create your feature branch (
git checkout -b feature/amazing) - Commit your changes (
git commit -m 'Add something amazing') - Push to the branch (
git push origin feature/amazing) - Open a Pull Request
License ๐
Apache 2.0 - do what you want, just don't blame us if something goes wrong. See LICENSE for the boring details.
- Built on top of AndroidX SplashScreen
- Powered by Jetpack Compose
- Inspired by modern app branding expectations
- Made with โ by kibotu
Contributors
Showing top 1 contributor by commit count.
