千家信息网

Jetpack Compose怎么实现动画效果

发表于:2024-10-10 作者:千家信息网编辑
千家信息网最后更新 2024年10月10日,这篇文章将为大家详细讲解有关Jetpack Compose怎么实现动画效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。概述compose 为支持动画提供了大量的
千家信息网最后更新 2024年10月10日Jetpack Compose怎么实现动画效果

这篇文章将为大家详细讲解有关Jetpack Compose怎么实现动画效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

概述

compose 为支持动画提供了大量的 api,通过这些 api 我们可以轻松实现动画效果

ps:这些 api 的原理与 Flutter 很接近,与原生的 api 相去甚远

你可以提前看看用 compose 实现的一个放大缩小动画,总的来说还是比较流畅:

低级别动画 API

animate*AsState

所能处理属性的种类:Float、Color、Dp、Size、Bounds、Offset、Rect、Int、IntOffset 和 IntSize

通过 animate*AsState 我们可以实现单一属性的动画效果,我们只需要提供目标值就可以自动从当前进度动画过渡到目标值

实现放大动画

1.代码

@Composablefun 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 = ""        )    }}

2.实现效果

实现颜色变化动画

1.代码

@Composablefun 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                )        ) {        }    }}

2.效果

使用 Animatable 实现颜色变化效果

Animatable 是一个值容器,我们可以通过调用 animateTo 实现动画效果。动画执行过程中如果再次开启动画会中断当前动画。

Animatable 动画执行过程中值的变化是在协程中执行的,所以 animateTo 是一个挂起操作

1.代码

@Composablefun 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 = Alignment.Center        ) {            Text(                text = "颜色动画",                style = TextStyle(color = Color.White, fontSize = 40.sp)            )        }    }}

2.效果

使用 updateTransition 实现颜色和圆角动画

使用 updateTransition 可以实现多个动画组合的效果。

例如:我们可以在动画执行过程中同时执行大小和颜色变化效果

本例中我们定义了一个枚举用来控制动画,枚举可以定义多个,分别用来对应动画的多个状态

1.代码

@Composablefun 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) BoxState.Expanded else BoxState.Collapsed                },contentAlignment = Alignment.Center        ) {            Text(text = "点击开始动画",style = TextStyle(color = Color.White,fontSize = 20.sp))        }    }}private enum class BoxState {    Collapsed,    Expanded}

2.效果

rememberInfiniteTransition

rememberInfiniteTransition 的使用和 updateTransition 基本一样,不同的是 rememberInfiniteTransition 的动画一旦开始便会一直反复运行下去,只有被移除动画才能结束

1.代码

@Composablefun 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 = Alignment.Center) {        Box(            Modifier                .fillMaxSize(0.8f)                .background(color),            contentAlignment = Alignment.Center        ) {            Text(                text = "公众号:安安安安卓 原创,禁抄袭",                style = TextStyle(color = Color.White, fontSize = 30.sp)            )        }    }}

2.效果

TargetBasedAnimation

TargetBasedAnimation 可以控制动画的执行时间,还可以延迟一段时间再开启动画。

1.代码

@Composablefun 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 {        mutableStateOf(0)    }    LaunchedEffect(state) {        val startTime = withFrameNanos { it }        println("进入协程:")        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))        }    }}

2.效果

自定义动画

AnimationSpec

AnimationSpec 可以自定义动画的行为,效果类似于原生动画中的估值器。

SpringSpec 弹簧效果

1.代码

@Composablefun 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))        }    }}

2.效果

TweenSpec 动画时间可控

1.代码

@Composablefun 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                }        ) {        }    }}

2.效果

FrameSpec

1.代码

@Composablefun 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                }        ) {        }    }}

2.效果

RepeatableSpec 实现有限次数的重复动画

执行有限次数动画后自动停止

1.代码

@Composablefun animrepeatableSpec() {    var state by remember {        mutableStateOf(true)    }    val value by animateIntAsState(        targetValue = if (state) 300 else 100,        animationSpec = repeatable(            iterations = 5,//动画重复执行的次数,设置多少就执行多少次            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                }        ) {        }    }}

2.效果

代码中设置了重复 5 次,所以反复执行五次后动画结束

InfiniteRepeatableSpec 无限次数执行动画

动画会无限次的执行下去,直到视图被移除

1.代码

@Composablefun 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 = "公众号:安安安安卓 原创,禁转载")        }    }}

2.效果

Easing

Easing 类似于我们原生动画中的差值器

有以下几种选择:

  • FastOutSlowInEasing

  • LinearOutSlowInEasing

  • FastOutLinearInEasing

  • LinearEasing

  • CubicBezierEasing

这几种实现的效果和 android 原生实现的动画差值器差距很大,甚至看不出有啥效果,所以代码我就不放了。有清楚原因的读者可以联系我

实现效果:

AnimationVector

大多数 Compose 动画 API 都支持将 Float、Color、Dp 以及其他基本数据类型作为开箱即用的动画值,但有时我们需要为其他数据类型(包括我们的自定义类型)添加动画效果

本例中实现颜色和大小的变换动画

代码中我们定义了一个 AnimSize 类,类中的第一个参数是颜色数据,第二个参数是尺寸数据。动画执行过程中会同事改变颜色和控件尺寸效果。

1.代码

@Composablefun 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(), it.v2)            }        )    )    println("颜色:${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)

2.效果

缺点是执行颜色变化过程中有闪烁

高级动画

高级动画一般指封装性较高的动画,使用较为简单,主要有以下三种:

因高级动画效果不明显,gif 很难展现出效果,所以这里不放代码和效果图了

  1. AnimatedVisibility

  2. animateContentSize

  3. Crossfade

关于"Jetpack Compose怎么实现动画效果"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

0