“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
- 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
- Implementation effect
Implement color change animation
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- The effect
TargetBasedAnimation
TargetBasedAnimation controls the animation’s execution time and can delay the animation for a certain amount of time.
- 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
- The effect
Custom animation
AnimationSpec
AnimationSpec customizes the behavior of an animation, similar to the estimator in native animation.
SpringSpec spring effect
- 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
- The effect
TweenSpec animation time is controllable
- 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
- The effect
FrameSpec
- 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
- The effect
RepeatableSpec implements a finite number of repeated animations
The animation stops automatically after executing a limited number of animations
- 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
- 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
- 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
- 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.
- 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
- 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
-
AnimatedVisibility
-
animateContentSize
-
Crossfade
Follow my public account “ananzhuo” to learn more knowledge