“This article has participated in the call for good writing activities, click to view: the back end, the big front end double track submission, 20,000 yuan prize pool waiting for you to challenge!”

Project git address: github.com/ananananzhu…

An overview of the

Compose provides a number of apis for animation support, which makes it easy to implement animation effects

Ps: The principle of these apis is very similar to that of Flutter and very different from the native API

You can check out a zooming in and out animation for Compose in advance, and it’s generally smooth:

Low level animation API

animate*AsState

Types of properties that can be handled: Float, Color, Dp, Size, Bounds, Offset, Rect, Int, IntOffset, and IntSize

With animate*AsState we can animate a single property. We can animate from the current progress to the target value automatically by providing the target value

Implement zoomed animation

  1. code
@Composable fun animSize() { val enable = remember { mutableStateOf(true) } val size = animateSizeAsState(targetValue = if (enable.value) Size(50f, 50f) else Size(300f, 300f)) Column( modifier = Modifier.fillMaxSize(1f), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Image( modifier = Modifier .size(size.value.width.dp, size.value.height.dp) .clickable { enable.value = ! enable.value }, painter = painterResource(id = R.drawable.apple), contentDescription = "" ) } }Copy the code
  1. Implementation effect

Implement color change animation

  1. code

@Composable
fun animColor() {
    val enable = remember {
        mutableStateOf(true)
    }
    val colors = animateColorAsState(targetValue = if (enable.value) Color.Green else Color.Red)
    val size = animateIntSizeAsState(
        targetValue = if (enable.value) IntSize(100, 100) else IntSize(
            300,
            300
        )
    )
    Column(
        modifier = Modifier.fillMaxWidth(1f),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Box(
            modifier = Modifier
                .size(size.value.width.dp, size.value.height.dp)
                .height(400.dp)
                .background(
                    color = colors.value,
                    shape = if (enable.value) RectangleShape else CircleShape
                )
        ) {

        }
    }
}
Copy the code
  1. The effect

Use Animatable to implement color change effects

Animatable is a value container that we can animate by calling animateTo. Animation will be interrupted if it is started again during animation execution.

The value changes during the execution of the Animatable animation are performed in the coroutine, so the animateTo is a pending operation

  1. code
@Composable fun animChangeColor() { val color = remember { Animatable(Color.Red) } val state = remember { mutableStateOf(true) } LaunchedEffect(state.value) { color.animateTo(if (state.value) Color.Red else Color.Magenta) } Box(Modifier.fillMaxSize(1f), contentAlignment = Alignment.Center) { Box( modifier = Modifier .background(color.value, shape = RoundedCornerShape(30.dp)) .size(200.dp) .clickable { state.value = ! State.value}, contentAlignment = align.center) {align (align = "align ", style = TextStyle(color = color.white, fontSize = 40.sp) ) } } }Copy the code
  1. The effect

Animate colors and rounded corners using updateTransition

Multiple animation combinations can be achieved using updateTransition.

For example, we can perform both size and color change effects during animation execution

In this example, we define an enumeration to control the animation. Enumerations can be multiple, one for each state of the animation

  1. code
@Composable fun animupdateTransition() { var state by remember { mutableStateOf(BoxState.Collapsed) } val transition = updateTransition(targetState = state, label = "") val round = transition.animateDp(label = "") { when (it) { BoxState.Collapsed -> 40.dp BoxState.Expanded -> 100.dp } } val color = transition.animateColor(label = "") { when (it) { BoxState.Collapsed -> Color.Red BoxState.Expanded -> Color.Green } } Box(Modifier.fillMaxSize(1f),contentAlignment = Alignment.Center) { Box( modifier =  Modifier .size(300.dp) .background( color.value, shape = RoundedCornerShape(corner = CornerSize(round.value)) ) .clickable { state = if (state == BoxState.Collapsed) Collapsed},contentAlignment = align.center) {Text(Text = "click to start animation ",style = TextStyle(color = Color.White,fontSize = 20.sp)) } } } private enum class BoxState { Collapsed, Expanded }Copy the code
  1. The effect

rememberInfiniteTransition

RememberInfiniteTransition updateTransition and use of the basic and same, different is rememberInfiniteTransition animation once begun will have been repeatedly run down and can end only removed the animation

  1. code
@Composable fun rememberInfiniteTransition1() { val infiniteTransition = rememberInfiniteTransition() val color by infiniteTransition.animateColor( initialValue = Color.Red, targetValue = Color.Green, animationSpec = infiniteRepeatable( animation = tween(1000, easing = LinearEasing), repeatMode = RepeatMode.Reverse ) ) Box(Modifier.fillMaxSize(1f), ContentAlignment = align.center) {Box(Modifier. FillMaxSize (0.8f). Background (color), ContentAlignment = align.center) {text-align (text-align =" Style = TextStyle(color = color.white, fontSize = 30.sp))}}}Copy the code
  1. The effect

TargetBasedAnimation

TargetBasedAnimation controls the animation’s execution time and can delay the animation for a certain amount of time.

  1. code
@Composable fun animTargetBasedAnimation() { var state by remember { mutableStateOf(0) } val anim = remember { TargetBasedAnimation( animationSpec = tween(2000), typeConverter = Float.VectorConverter, initialValue = 100f, targetValue = 300f ) } var playTime by remember { mutableStateOf(0L) } var animationValue by remember { LaunchedEffect(state) {val startTime = withFrameNanos {it} println(" enter the coroutine: ") do { playTime = withFrameNanos { it } - startTime animationValue = anim.getValueFromNanos(playTime).toInt() } while (! anim.isFinishedFromNanos(playTime)) } Box(modifier = Modifier.fillMaxSize(1f),contentAlignment = Alignment.Center) { Box(modifier = Modifier .size(animationValue.dp) .background(Color.Red,shape = RoundedCornerShape(animationValue/5)) .clickable { state++ },contentAlignment = Alignment.Center) { Text(text = animationValue.toString(),style = TextStyle(color = Color.White,fontSize = (animationValue/5).sp)) } } }Copy the code
  1. The effect

Custom animation

AnimationSpec

AnimationSpec customizes the behavior of an animation, similar to the estimator in native animation.

SpringSpec spring effect

  1. code
@Composable
fun animSpring() {
    val state = remember {
        mutableStateOf(true)
    }
    var value = animateIntAsState(
        targetValue = if (state.value) 300 else 100,
        animationSpec = spring(
            dampingRatio = Spring.DampingRatioHighBouncy,
            stiffness = Spring.StiffnessVeryLow
        )
    )

    Box(
        Modifier
            .fillMaxSize(1f)
            .padding(start = 30.dp), contentAlignment = Alignment.CenterStart
    ) {
        Box(
            Modifier
                .width(value.value.dp)
                .height(80.dp)
                .background(Color.Red, RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp))
                .clickable {
                    state.value = !state.value
                }, contentAlignment = Alignment.CenterStart
        ) {
            Text(text = "哈哈哈", style = TextStyle(color = Color.White, fontSize = 20.sp))
        }
    }
}
Copy the code
  1. The effect

TweenSpec animation time is controllable

  1. code
@Composable fun animTweenSpec() { val state = remember { mutableStateOf(true) } val value = animateIntAsState( targetValue = if (state.value) 300 else 100, animationSpec = tween( durationMillis = 1500, delayMillis = 200, easing = LinearEasing ) ) Box( Modifier .fillMaxSize(1f) .padding(start = 50.dp), contentAlignment = Alignment.CenterStart ) { Box( Modifier .width(value.value.dp) .height(100.dp) .background(Color.Red,  RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp)) .clickable { state.value = ! state.value } ) { } } }Copy the code
  1. The effect

FrameSpec

  1. code
@Composable fun animkeyframesSpec() { var state by remember { mutableStateOf(true) } val value by animateIntAsState( targetValue = if (state) 300 else 100, animationSpec = keyframes { durationMillis = 2000 0 at 700 with LinearOutSlowInEasing 700 at 1400 with FastOutLinearInEasing 1400 at 2000 }) Box(Modifier.fillMaxSize(1f), contentAlignment = Alignment.CenterStart) { Box( Modifier .width(value.dp) .height(100.dp) .background(Color.Red, RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp)) .clickable { state = ! state } ) { } } }Copy the code
  1. The effect

RepeatableSpec implements a finite number of repeated animations

The animation stops automatically after executing a limited number of animations

  1. code
@Composable fun animrepeatableSpec() { var state by remember { mutableStateOf(true) } val value by animateIntAsState( TargetValue = if (state) 300 else 100, animationSpec = REPEATable (Iterations = 5,// Number of iterations of animation, Animation = tween(durationMillis = 1000) as many times as you set repeatMode = RepeatMode.Reverse ) ) Box( Modifier .fillMaxSize(1f) .padding(start = 30.dp), contentAlignment = Alignment.CenterStart) { Box( Modifier .width(value.dp) .height(100.dp) .background(Color.Red, RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp)) .clickable { state = ! state } ) { } } }Copy the code
  1. The effect

The code is set to repeat 5 times, so the animation ends after 5 repetitions

InfiniteRepeatableSpec executes animation an infinite number of times

The animation is executed an infinite number of times until the view is removed

  1. code
@Composable fun animinfiniteRepeatableSpec() { var state by remember { mutableStateOf(true) } val value by animateIntAsState( targetValue = if (state) 300 else 100, animationSpec = infiniteRepeatable( animation = tween(durationMillis = 1000), repeatMode = RepeatMode.Reverse ) ) Box( Modifier .fillMaxSize(1f) .padding(start = 30.dp), contentAlignment = Alignment.CenterStart) { Box( Modifier .width(value.dp) .height(100.dp) .background(Color.Red, RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp)) .clickable { state = ! State}) {Text(Text = "下 载")}}}Copy the code
  1. The effect

Easing

Easing is similar to the differentiator in our native animations

There are several options:

  • FastOutSlowInEasing
  • LinearOutSlowInEasing
  • FastOutLinearInEasing
  • LinearEasing
  • CubicBezierEasing

The effect of these implementations is very different from the android native implementation of the animation differentiator, or even the effect is not visible, so I will not put the code. Readers with a clear reason should contact me

Effect:

AnimationVector

Most Compose animation apis support Float, Color, Dp, and other basic data types as out-of-the-box animation values, but sometimes we need to add animation effects for other data types, including our own custom types

In this example, the color and size transform animation is implemented

In this code we define an AnimSize class. The first parameter of the class is the color data and the second parameter is the size data. The animation changes color and control size effects during execution.

  1. code
@Composable fun animAnimationVector() { var state by remember { mutableStateOf(true) } val value by animateValueAsState(  targetValue = if (state) AnimSize(0xffff5500, 100f) else AnimSize(0xff00ff00, 300f), typeConverter = TwoWayConverter( convertToVector = { // AnimationVector2D(target.color.toFloat(), target.size) AnimationVector2D(it.color.toFloat(), it.size) }, convertFromVector = { AnimSize(it.v1.toLong(), }) println(" color :${value.color}") Box(modifier = modifier.fillmaxSize (1f).padding(30.dp), contentAlignment = Alignment.Center) { Box( modifier = Modifier .size(value.size.dp) // .size(300.dp) .background(Color(value.color), RoundedCornerShape(30.dp)) .clickable { state = ! state } ) { } } } data class AnimSize(val color: Long, val size: Float)Copy the code
  1. The effect

The disadvantage is that there is flicker during performing color changes

Advanced animation

Advanced animation generally refers to the animation with high encapsulation and is relatively simple to use. There are three main types:

Because advanced animation is not obvious, giFs are difficult to show, so I won’t put the code and renderings here

  1. AnimatedVisibility

  2. animateContentSize

  3. Crossfade

Follow my public account “ananzhuo” to learn more knowledge