Slide 1

Slide 1 text

Erik Manberger Jetpack Compose Animations

Slide 2

Slide 2 text

Why use animations? • Add visual cues to notify what’s going on in your app • When UI changes state • Higher quality look and feel

Slide 3

Slide 3 text

Jetpack Compose Animations • High-level animation APIs • Many APIs available as Composable functions • Backed by lower-level APIs built with Kotlin coroutine suspend functions

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

AnimatedVisibility • Animates appearance/disappearance of content • Visible parameter • Customise with EnterTransition/ExitTransition • Fade, Expand/Shrink, Scale, Slide


Slide 6

Slide 6 text

AnimatedVisibility @Composable fun AnimatedVisibility( visible: Boolean, modifier: Modifier = Modifier, enter: EnterTransition = fadeIn() + expandIn(), exit: ExitTransition = shrinkOut() + fadeOut(), label: String = "AnimatedVisibility", content: @Composable() AnimatedVisibilityScope.() -> Unit ) { val transition = updateTransition(visible, label) AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content) }

Slide 7

Slide 7 text

AnimatedVisibility @Composable fun ToggleGreeting() { var visible by remember { mutableStateOf(false) } Button(onClick = { visible = !visible }) { Text(text = "Greetings") } if (visible) { Text(text = "Hello Android!!") } }

Slide 8

Slide 8 text

AnimatedVisibility @Composable fun ToggleGreeting() { var visible by remember { mutableStateOf(false) } Button(onClick = { visible = !visible }) { Text(text = "Greetings") } AnimatedVisibility (visible) { Text(text = "Hello Android!!") } }

Slide 9

Slide 9 text

AnimatedContent • A container that animates content automatically • targetState • ContentTransform • transistionSpec to customise

Slide 10

Slide 10 text

AnimatedContent @Composable fun AnimatedContent( targetState: S, modifier: Modifier = Modifier, transitionSpec: AnimatedContentScope.() -> ContentTransform contentAlignment: Alignment, content: @Composable() AnimatedVisibilityScope.(targetState: S) -> Unit ) class ContentTransform( val targetContentEnter: EnterTransition, val initialContentExit: ExitTransition, targetContentZIndex: Float = 0f, sizeTransform: SizeTransform? = SizeTransform() )

Slide 11

Slide 11 text

AnimatedContent @Composable fun AnimatedCount() { Column { var count by remember { mutableStateOf(0) } Button(onClick = { count++ }) { Text("Add") } AnimatedContent(targetState = count) { targetCount -> Text(text = "Count: $targetCount") } } }

Slide 12

Slide 12 text

CrossFade • Switch between two layouts • When targetState is changed animation is triggered • FiniteAnimationSpec con fi gures animation

Slide 13

Slide 13 text

CrossFade @Composable fun Crossfade( targetState: T, modifier: Modifier = Modifier, animationSpec: FiniteAnimationSpec = tween(), label: String = "Crossfade", content: @Composable (T) -> Unit ) { val transition = updateTransition(targetState, label) transition.Crossfade(modifier, animationSpec, content = content) }

Slide 14

Slide 14 text

CrossFade var isGreen by remember { mutableStateOf(false) } Crossfade(targetState = isGreen) { target -> when (target) { true -> Text("CrossFade", color = Color.Green) else -> Text("CrossFade") } }

Slide 15

Slide 15 text

animateContentSize • Animates its own size when child modi fi er/Composable changes size • FiniteAnimationSpec can specify animation • A fi nishedListener can notify when size animation is done

Slide 16

Slide 16 text

fun Modifier.animateContentSize( animationSpec: FiniteAnimationSpec = spring(), finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null ): Modifier animateContentSize

Slide 17

Slide 17 text

animateContentSize @Composable fun AnimateContentSize() { var showAll by remember { mutableStateOf(false) } val maxLines = if (showAll) Int.MAX_VALUE else 1 Column(modifier = Modifier.animateContentSize()) { Button() Text(maxLines = maxLines) } }

Slide 18

Slide 18 text

animateValueAsState • Easiest animation API for animating single value • Provide target value animates to that from current value • Customise with AnimationSpec • Float, Color, Dp, Size, O ff set, Rect, Int, IntO ff set and IntSize

Slide 19

Slide 19 text

animateValueAsState @Composable fun animateValueAsState( targetValue: T, typeConverter: TwoWayConverter, animationSpec: AnimationSpec = remember { spring() }, visibilityThreshold: T? = null, label: String = "ValueAnimation", finishedListener: ((T) -> Unit)? = null ): State

Slide 20

Slide 20 text

animateValueAsState val size by animateDpAsState( targetValue = if (isExpanded) 160.dp else 80.dp ) Box( modifier = Modifier .size(size) .background(Color.Green) )

Slide 21

Slide 21 text

updateTransition • Creates and remembers an instance of Transition • Transition manages 1+ animations runs simultaneously between states • Use animateValue for child animations • Use enum type to ensure type safety • Used in AnimatedVisibility, AnimatedContent, CrossFade

Slide 22

Slide 22 text

@Composable fun updateTransition( targetState: T, label: String? = null ): Transition { val transition = remember { Transition(targetState, label = label) } transition.animateTo(targetState) DisposableEffect(transition) { onDispose { transition.onTransitionEnd() } } return transition } updateTransition

Slide 23

Slide 23 text

enum class Shape { Rectangle, Circle } updateTransition

Slide 24

Slide 24 text

var currentShape by remember { mutableStateOf(Shape.Rectangle) } val transition = updateTransition(targetState = currentShape) val cornerRadius by transition.animateDp { targetShape -> when (shape) { Shape.Rectangle -> 0.dp Shape.Circle -> size/2 } } val color by transition.animateColor { targetShape -> when (shape) { Shape.Rectangle -> Color.Green Shape.Circle -> Color.Red } } Box(modifier = Modifier .size(size) .clip(RoundedCornerShape(cornerRadius)) .background(color) ) updateTransition

Slide 25

Slide 25 text

rememberInfiniteTransition • Creates an instance of In fi niteTransition • Animations start immediately & don’t stop • Set AnimationSpec with in fi niteRepeatable • Child animations: animateColor, animateFloat, …, animateValue

Slide 26

Slide 26 text

@Composable fun rememberInfiniteTransition(): InfiniteTransition { val infiniteTransition = remember { InfiniteTransition() } infiniteTransition.run() return infiniteTransition } rememberInfiniteTransition

Slide 27

Slide 27 text

@Composable fun RememberInfiniteTransition() { val infiniteTransition = rememberInfiniteTransition() val degree by infiniteTransition.animateFloat( initialValue = 0f, targetValue = 45f, animationSpec = infiniteRepeatable( animation = tween(500), repeatMode = RepeatMode.Reverse ) ) Canvas(modifier = Modifier.size(160.dp), onDraw = { drawArc( color = Color.Yellow, startAngle = degree, sweepAngle = 360f - 2*degree, useCenter = true ) }) } rememberInfiniteTransition

Slide 28

Slide 28 text

Animatable • Coroutine-based API for animating a single value • Animates value when changed via animateTo • Ongoing animation will be cancelled when new animation is started • Float, Color • Used in animateValueAsState

Slide 29

Slide 29 text

Animation • Animation calculation engine that higher-level APIs use • Use to manually control animation time • TargetBasedAnimation, DecayAnimation

Slide 30

Slide 30 text

AnimationSpec • spring(dampingRatio, sti ff ness) • tween(durationMillis, delayMillis, easing) • keyframes(durationMillis, ranges, easing) • repeatable(iterations, animation, repeatMode) • in fi niteRepeatable(animation, repeatMode) • snap(delayMillis)

Slide 31

Slide 31 text

Easing • Adjust animations fraction • Change animation speed • fun(0-1.0): Float

Slide 32

Slide 32 text

Summary • High-level APIs, easy to use • Start out with AnimatedVisibility and animateContentSize • https://developer.android.com/jetpack/compose/animation

Slide 33

Slide 33 text

Thank you