😸 Animations with Jetpack Compose
Antoine ROBIEZ
@enthuan
Baptiste CARLIER
@bapness
How to give life to your apps
Animate:
1. Give the appearance of movement using animation
techniques
2. Bring something to life
Jetpack Compose
• Declarative UI
• Kotlin
• Less code
• Compatible
Component = States
View = States
Screen = States
The purr-fect
Application
Jari Hytönen
Visibility Colors Rotation
Live coding
Visibility
AnimatedVisibility(fabExpand) {
Text(
modifier = Modifier.padding(horizontal = 8.dp),
text = "Trier"
)
}
Live coding results
val scaleY by animateFloatAsState(
targetValue = (if (sorted) {
-1f
} else {
1f
}),
animationSpec = tween(durationMillis = 500, easing = FastOutSlowInEasing)
)
Icon(
modifier = Modifier.scale(1f, scaleY),
imageVector = fabIcon,
contentDescription = null
)
Live coding results
AnimatedVisibility(
visible = expandState,
enter = slideInVertically(
initialOffsetY = { fullHeight -> fullHeight * -1 },
animationSpec = tween(durationMillis = 150, easing =
LinearOutSlowInEasing)
),
exit = slideOutVertically(
targetOffsetY = { fullHeight -> (fullHeight * -1) },
animationSpec = tween(durationMillis = 150, easing =
FastOutLinearInEasing)
)
) {
Text(
modifier = Modifier.padding(16.dp),
style = MaterialTheme.typography.bodyMedium,
text = cat.temper
)
}
Live coding results
• Use AnimatedVisibility(visible) to show/hide a
Composable
• Ability to customize enter / exit transitions
• Use AnimatedVisibilityScope with
Modifier.animateEnterExit(), you specify the child
element animation
Visibility
Visibility
Rotation
val arrowRotation by animateFloatAsState(
targetValue = (if (expandState) {
-180f
} else {
0f
}),
animationSpec = tween(durationMillis = 500, easing = FastOutSlowInEasing)
)
Icon(
modifier = Modifier
.padding(16.dp)
.rotate(arrowRotation)
,
imageVector = Icons.Filled.KeyboardArrowUp,
contentDescription = "Back"
)
Live coding results
Visibility
Rotation
Colors
val animationSpec = tween<Color>(400)
val contentColor = animateColorAsState(
targetValue = if (isFav) {
MaterialTheme.colorScheme.onPrimary
} else {
MaterialTheme.colorScheme.onSurface
},
animationSpec = animationSpec
)
val containerColor = animateColorAsState(
targetValue = if (isFav) {
MaterialTheme.colorScheme.primary
} else {
MaterialTheme.colorScheme.surface
},
animationSpec = animationSpec
)
Live coding results
Animate property from a State
• Use animate*AsState() APIs for value-based animation
• The animation is customizable with AnimationSpec
• Available animations:
animateDpAsState()
animateOffsetAsState()
animateFloatAsState()
animateColorAsState()
animateSizeAsState()
animateRectAsState()
animateIntAsState()
Interpolators
Linear Slow-In
Fast-Out
Slow-Out Slow-In-
Slow-Out
Live coding
Lists
Animated
Vector Drawable
ShapeShifter
https://shapeshifter.design/
var atEnd by remember { mutableStateOf(false) }
val fabIcon =
AnimatedImageVector.animatedVectorResource(R.drawable.avd_anim)
Icon(
painter = rememberAnimatedVectorPainter(fabIcon, atEnd),
contentDescription = null
)
Live coding results
Animated Vector Drawable
• Bound to a state (boolean)
• AnimatedImageVector:
✓ AnimatedImageVector.animatedVectorResource
• Painter:
✓ rememberAnimatedVectorPainter(vector, state)
• To trigger the animation, just reverse the state:
✓ state = !state
val onInverseSort = {
sorted = !sorted
coroutineScope.launch {
delay(200)
lazyListState.animateScrollToItem(0)
}
}
LazyColumn(
modifier = Modifier.fillMaxSize().padding(it),
state = lazyListState
) {
items(items = myItems, key = { it.id }) { cat ->
CatView(
modifier = Modifier
.fillMaxWidth()
.animateItemPlacement()
.clickable { onGoDetail(cat.id.toString()) }
.padding(horizontal = 24.dp, vertical = 16.dp),
cat = cat
)
}
}
Live coding results
• LazyItemScope:
✓ animateItemPlacement
• LazyListState:
✓ animateScrollToItem
✓ animateScrollBy
• Goodbye DiffUtils
Animate lists
Live coding
Transitions between screens
With a NavHost based navigation
Transitions
• AnimatedNavHost replaces NavHost
• Same mechanism than XML enter/exit/popEnter/popExit
• Not yet into Compose AndroidX
✓ Use Accompanist library
• Missing : SharedElement between screens
Navigation transitions
val onInverseSort = {
sorted = !sorted
coroutineScope.launch {
delay(200)
lazyListState.animateScrollToItem(0)
}
}
LazyColumn(
modifier = Modifier.fillMaxSize().padding(it),
state = lazyListState
) {
items(items = myItems, key = { it.id }) { cat ->
CatView(
modifier = Modifier
.fillMaxWidth()
.animateItemPlacement()
.clickable { onGoDetail(cat.id.toString()) }
.padding(horizontal = 24.dp, vertical = 16.dp),
cat = cat
)
}
}
Live coding results
Live coding
SplashScreen
Loading
Animations avec Compose : rendez vos apps chat-oyantes
Specifications, loops, transitions
AnimationSpecs allow to define how values should transform:
• tween: animates over the specified duration using an easing curve
• spring: a physics-based animation
• keyframes: based on the snapshot values specified at different timestamps
in the duration of the animation
• repeatable: repeat until it reaches the specified iteration count + a
animation (tween, spring, …)
• infiniteRepeatable: as repeatable, but indefinitely
• snap: immediately switches the value to the end value
Keyframes
val infiniteTransition = rememberInfiniteTransition()
val assRotation by infiniteTransition.animateFloat(
initialValue = -20f,
targetValue = -20f,
animationSpec = infiniteRepeatable(
animation = keyframes {
durationMillis = 1200
-20.0f at 0 with LinearOutSlowInEasing
20f at 600 with LinearOutSlowInEasing
-20f at 1200 with LinearOutSlowInEasing
},
repeatMode = RepeatMode.Restart
)
)
Box(modifier = modifier) {
Image(
painter = painterResource(id = R.drawable.cat_layer_back),
contentDescription = "Twerking cat",
modifier = Modifier.fillMaxSize()
.graphicsLayer {
rotationZ = assRotation
},
contentScale = ContentScale.Fit
)
Image(
painter = painterResource(id = R.drawable.cat_layer_front),
contentDescription = "",
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Fit
)
}
Live coding results
Live coding
At launch
LaunchedEffect
val animatable = remember { Animatable(0f) }
LaunchedEffect(Unit) {
delay(800)
animatable.animateTo(targetValue = value, animationSpec = tween(2000))
}
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
Text(
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.SemiBold,
text = label
)
LinearProgressIndicator(
modifier = Modifier
.fillMaxWidth()
.height(8.dp)
.clip(RoundedCornerShape(4.dp)),
progress = animatable.value,
color = color,
trackColor = color.copy(alpha = 0.4f)
)
}
Live coding results
LaunchedEffect
• LaunchedEffect is triggered during the composition
• The animation runs even if the Composable isn’t displayed on
screen
• Be careful with LazyLayout items
➢ LaunchedEffect is called each time the view is displayed
It's easy
Set the right animation,
at the right time
Pay attention to physics
Animated Vector Drawable :
usable ?
useful ?
is it worth it ?
MotionLayout :
MotionLayout :
Animated Vector Drawable : is it worth it ?
usable ?
useful ?
Animated Vector Drawable :
MotionLayout : usable ?
useful ?
is it worth it ?
One screen =
Several components
Several views
Several states
Ask for animated mockups or wireframes
Android community needs you
your client needs you
your final user needs you
Just try it !
https://github.com/enthuan/compose-animations
Antoine ROBIEZ
@enthuan
Baptiste CARLIER
@bapness

More Related Content

PDF
OPAL-RT Real time simulation using RT-LAB
PDF
BE-EEE-8th sem project report for the project titled "Asymmetrical Multilevel...
DOC
Difference between c v
PPTX
Three level inverter
PPT
Matrix based AC-DC converter
PDF
کارآموزی
PPTX
Basics of SVPWM technique by Hardik Panyda
PPTX
About Sine Pulse Width Modulation
OPAL-RT Real time simulation using RT-LAB
BE-EEE-8th sem project report for the project titled "Asymmetrical Multilevel...
Difference between c v
Three level inverter
Matrix based AC-DC converter
کارآموزی
Basics of SVPWM technique by Hardik Panyda
About Sine Pulse Width Modulation

Similar to Animations avec Compose : rendez vos apps chat-oyantes (20)

PPTX
Intro to Canva
PDF
Creating an Uber Clone - Part IV - Transcript.pdf
PDF
Introduction to Canvas - Toronto HTML5 User Group
PPTX
Introduction to Canvas - Toronto HTML5 User Group
KEY
openFrameworks 007 - graphics
PPTX
canvas_1.pptx
PDF
SwiftUI Animation - The basic overview
PDF
Enhancing UI/UX using Java animations
PDF
Standford 2015 week4: 1.Protocols and Delegation, Gestures 2. Multiple MVCs
PDF
Expand/Collapse animation on Android
PDF
Fabric.js @ Falsy Values
PDF
Model View Intent on Android
PDF
Animate The Web With Ember.js - Jessica Jordan
PDF
Jetpack Compose - Hands-on February 2020
PPTX
JavaFX 2.0 and Alternative Languages
PPTX
How to Create Animation Using the AnimatedAlign Widget.pptx
PPT
HTML5 Canvas
PPTX
Kotlin Mullets
PDF
Real life XNA
PDF
Swift, via "swift-2048"
Intro to Canva
Creating an Uber Clone - Part IV - Transcript.pdf
Introduction to Canvas - Toronto HTML5 User Group
Introduction to Canvas - Toronto HTML5 User Group
openFrameworks 007 - graphics
canvas_1.pptx
SwiftUI Animation - The basic overview
Enhancing UI/UX using Java animations
Standford 2015 week4: 1.Protocols and Delegation, Gestures 2. Multiple MVCs
Expand/Collapse animation on Android
Fabric.js @ Falsy Values
Model View Intent on Android
Animate The Web With Ember.js - Jessica Jordan
Jetpack Compose - Hands-on February 2020
JavaFX 2.0 and Alternative Languages
How to Create Animation Using the AnimatedAlign Widget.pptx
HTML5 Canvas
Kotlin Mullets
Real life XNA
Swift, via "swift-2048"
Ad

Recently uploaded (20)

PDF
Enhancing emotion recognition model for a student engagement use case through...
PDF
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
PDF
Taming the Chaos: How to Turn Unstructured Data into Decisions
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PDF
Hybrid model detection and classification of lung cancer
PDF
Getting started with AI Agents and Multi-Agent Systems
PDF
STKI Israel Market Study 2025 version august
PDF
A review of recent deep learning applications in wood surface defect identifi...
PDF
Zenith AI: Advanced Artificial Intelligence
PDF
Unlock new opportunities with location data.pdf
PDF
1 - Historical Antecedents, Social Consideration.pdf
PDF
A novel scalable deep ensemble learning framework for big data classification...
PDF
A comparative study of natural language inference in Swahili using monolingua...
PPTX
observCloud-Native Containerability and monitoring.pptx
PDF
Hybrid horned lizard optimization algorithm-aquila optimizer for DC motor
PPTX
Web Crawler for Trend Tracking Gen Z Insights.pptx
PPTX
Chapter 5: Probability Theory and Statistics
PDF
WOOl fibre morphology and structure.pdf for textiles
PDF
A Late Bloomer's Guide to GenAI: Ethics, Bias, and Effective Prompting - Boha...
PDF
NewMind AI Weekly Chronicles – August ’25 Week III
Enhancing emotion recognition model for a student engagement use case through...
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
Taming the Chaos: How to Turn Unstructured Data into Decisions
Univ-Connecticut-ChatGPT-Presentaion.pdf
Hybrid model detection and classification of lung cancer
Getting started with AI Agents and Multi-Agent Systems
STKI Israel Market Study 2025 version august
A review of recent deep learning applications in wood surface defect identifi...
Zenith AI: Advanced Artificial Intelligence
Unlock new opportunities with location data.pdf
1 - Historical Antecedents, Social Consideration.pdf
A novel scalable deep ensemble learning framework for big data classification...
A comparative study of natural language inference in Swahili using monolingua...
observCloud-Native Containerability and monitoring.pptx
Hybrid horned lizard optimization algorithm-aquila optimizer for DC motor
Web Crawler for Trend Tracking Gen Z Insights.pptx
Chapter 5: Probability Theory and Statistics
WOOl fibre morphology and structure.pdf for textiles
A Late Bloomer's Guide to GenAI: Ethics, Bias, and Effective Prompting - Boha...
NewMind AI Weekly Chronicles – August ’25 Week III
Ad

Animations avec Compose : rendez vos apps chat-oyantes

  • 1. 😸 Animations with Jetpack Compose Antoine ROBIEZ @enthuan Baptiste CARLIER @bapness How to give life to your apps
  • 2. Animate: 1. Give the appearance of movement using animation techniques 2. Bring something to life
  • 3. Jetpack Compose • Declarative UI • Kotlin • Less code • Compatible
  • 10. AnimatedVisibility(fabExpand) { Text( modifier = Modifier.padding(horizontal = 8.dp), text = "Trier" ) } Live coding results
  • 11. val scaleY by animateFloatAsState( targetValue = (if (sorted) { -1f } else { 1f }), animationSpec = tween(durationMillis = 500, easing = FastOutSlowInEasing) ) Icon( modifier = Modifier.scale(1f, scaleY), imageVector = fabIcon, contentDescription = null ) Live coding results
  • 12. AnimatedVisibility( visible = expandState, enter = slideInVertically( initialOffsetY = { fullHeight -> fullHeight * -1 }, animationSpec = tween(durationMillis = 150, easing = LinearOutSlowInEasing) ), exit = slideOutVertically( targetOffsetY = { fullHeight -> (fullHeight * -1) }, animationSpec = tween(durationMillis = 150, easing = FastOutLinearInEasing) ) ) { Text( modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.bodyMedium, text = cat.temper ) } Live coding results
  • 13. • Use AnimatedVisibility(visible) to show/hide a Composable • Ability to customize enter / exit transitions • Use AnimatedVisibilityScope with Modifier.animateEnterExit(), you specify the child element animation Visibility
  • 15. val arrowRotation by animateFloatAsState( targetValue = (if (expandState) { -180f } else { 0f }), animationSpec = tween(durationMillis = 500, easing = FastOutSlowInEasing) ) Icon( modifier = Modifier .padding(16.dp) .rotate(arrowRotation) , imageVector = Icons.Filled.KeyboardArrowUp, contentDescription = "Back" ) Live coding results
  • 17. val animationSpec = tween<Color>(400) val contentColor = animateColorAsState( targetValue = if (isFav) { MaterialTheme.colorScheme.onPrimary } else { MaterialTheme.colorScheme.onSurface }, animationSpec = animationSpec ) val containerColor = animateColorAsState( targetValue = if (isFav) { MaterialTheme.colorScheme.primary } else { MaterialTheme.colorScheme.surface }, animationSpec = animationSpec ) Live coding results
  • 18. Animate property from a State • Use animate*AsState() APIs for value-based animation • The animation is customizable with AnimationSpec • Available animations: animateDpAsState() animateOffsetAsState() animateFloatAsState() animateColorAsState() animateSizeAsState() animateRectAsState() animateIntAsState()
  • 22. var atEnd by remember { mutableStateOf(false) } val fabIcon = AnimatedImageVector.animatedVectorResource(R.drawable.avd_anim) Icon( painter = rememberAnimatedVectorPainter(fabIcon, atEnd), contentDescription = null ) Live coding results
  • 23. Animated Vector Drawable • Bound to a state (boolean) • AnimatedImageVector: ✓ AnimatedImageVector.animatedVectorResource • Painter: ✓ rememberAnimatedVectorPainter(vector, state) • To trigger the animation, just reverse the state: ✓ state = !state
  • 24. val onInverseSort = { sorted = !sorted coroutineScope.launch { delay(200) lazyListState.animateScrollToItem(0) } } LazyColumn( modifier = Modifier.fillMaxSize().padding(it), state = lazyListState ) { items(items = myItems, key = { it.id }) { cat -> CatView( modifier = Modifier .fillMaxWidth() .animateItemPlacement() .clickable { onGoDetail(cat.id.toString()) } .padding(horizontal = 24.dp, vertical = 16.dp), cat = cat ) } } Live coding results
  • 25. • LazyItemScope: ✓ animateItemPlacement • LazyListState: ✓ animateScrollToItem ✓ animateScrollBy • Goodbye DiffUtils Animate lists
  • 26. Live coding Transitions between screens With a NavHost based navigation
  • 28. • AnimatedNavHost replaces NavHost • Same mechanism than XML enter/exit/popEnter/popExit • Not yet into Compose AndroidX ✓ Use Accompanist library • Missing : SharedElement between screens Navigation transitions
  • 29. val onInverseSort = { sorted = !sorted coroutineScope.launch { delay(200) lazyListState.animateScrollToItem(0) } } LazyColumn( modifier = Modifier.fillMaxSize().padding(it), state = lazyListState ) { items(items = myItems, key = { it.id }) { cat -> CatView( modifier = Modifier .fillMaxWidth() .animateItemPlacement() .clickable { onGoDetail(cat.id.toString()) } .padding(horizontal = 24.dp, vertical = 16.dp), cat = cat ) } } Live coding results
  • 32. Specifications, loops, transitions AnimationSpecs allow to define how values should transform: • tween: animates over the specified duration using an easing curve • spring: a physics-based animation • keyframes: based on the snapshot values specified at different timestamps in the duration of the animation • repeatable: repeat until it reaches the specified iteration count + a animation (tween, spring, …) • infiniteRepeatable: as repeatable, but indefinitely • snap: immediately switches the value to the end value
  • 34. val infiniteTransition = rememberInfiniteTransition() val assRotation by infiniteTransition.animateFloat( initialValue = -20f, targetValue = -20f, animationSpec = infiniteRepeatable( animation = keyframes { durationMillis = 1200 -20.0f at 0 with LinearOutSlowInEasing 20f at 600 with LinearOutSlowInEasing -20f at 1200 with LinearOutSlowInEasing }, repeatMode = RepeatMode.Restart ) ) Box(modifier = modifier) { Image( painter = painterResource(id = R.drawable.cat_layer_back), contentDescription = "Twerking cat", modifier = Modifier.fillMaxSize() .graphicsLayer { rotationZ = assRotation }, contentScale = ContentScale.Fit ) Image( painter = painterResource(id = R.drawable.cat_layer_front), contentDescription = "", modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Fit ) } Live coding results
  • 37. val animatable = remember { Animatable(0f) } LaunchedEffect(Unit) { delay(800) animatable.animateTo(targetValue = value, animationSpec = tween(2000)) } Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { Text( style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.SemiBold, text = label ) LinearProgressIndicator( modifier = Modifier .fillMaxWidth() .height(8.dp) .clip(RoundedCornerShape(4.dp)), progress = animatable.value, color = color, trackColor = color.copy(alpha = 0.4f) ) } Live coding results
  • 38. LaunchedEffect • LaunchedEffect is triggered during the composition • The animation runs even if the Composable isn’t displayed on screen • Be careful with LazyLayout items ➢ LaunchedEffect is called each time the view is displayed
  • 39. It's easy Set the right animation, at the right time Pay attention to physics
  • 40. Animated Vector Drawable : usable ? useful ? is it worth it ? MotionLayout :
  • 41. MotionLayout : Animated Vector Drawable : is it worth it ? usable ? useful ?
  • 42. Animated Vector Drawable : MotionLayout : usable ? useful ? is it worth it ?
  • 43. One screen = Several components Several views Several states Ask for animated mockups or wireframes
  • 44. Android community needs you your client needs you your final user needs you Just try it !

Editor's Notes

  • #24: ARO Concernant les animated vector drawable, c’est un peu étrange mais ça reste dans la logique compose. On doit avoir un état (eh oui encore) lié à l’animated Vector Drawable, récupérer la resource. Préparer un painter qui va bien sur etre remembered entre les compositions et le passer en attribut d’une image. Pour déclencher l’animation, on inversera simplement le booléen (au clic ou autre)