前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >compose--动画

compose--动画

作者头像
aruba
发布2022-12-15 15:02:45
9370
发布2022-12-15 15:02:45
举报
文章被收录于专栏:android技术android技术

compose中本身封装了很多动画,我们可以拿来直接使用,动画也可以从官网进行学习:Compose动画

一、AnimationSpec

compose中的动画效果都是由AnimationSpec定义的,它包含了动画执行时长,估值器,插值器的功能,我们也可以通过AnimationSpec自定义动画效果,所以在真正使用compose动画之前,先对AnimationSpec来做学习

1.spring

spring就是一个弹弹乐效果的插值器,stiffness 定义弹簧应向结束值移动的速度,dampingRatio 定义弹簧的弹性,官方给出的效果图示如下:

例子:

代码语言:javascript
复制
@Preview
@Composable
fun MySpring() {
    var targetValue by remember { mutableStateOf(0.dp) }
    val paddingTop by animateDpAsState(
        targetValue = targetValue,
        animationSpec = spring(
            dampingRatio = Spring.DampingRatioHighBouncy,
            stiffness = Spring.StiffnessMedium
        )
    )

    Box(
        modifier = Modifier
            .padding(top = paddingTop)// 上边距随动画值而变化
            .width(50.dp)
            .height(50.dp)
            .background(Color.Blue)
            .clickable {
                targetValue = 100.dp
            }
    )
}

效果:

2.tween

tween用于指定动画执行时间 durationMillis、延迟执行时间 delayMillis 、运动速率变化 easing

2.1 基本使用
代码语言:javascript
复制
@Preview
@Composable
fun MyTween() {
    var targetValue by remember { mutableStateOf(0.dp) }
    val paddingTop by animateDpAsState(
        targetValue = targetValue,
        animationSpec = tween(2000)
    )

    Box(
        modifier = Modifier
            .padding(top = paddingTop)// 上边距随动画值而变化
            .width(50.dp)
            .height(50.dp)
            .background(Color.Blue)
            .clickable {
                targetValue = 100.dp
            }
    )
}

效果:

2.2 easing

运动速率变化默认提供了以下几种,不指定时使用FastOutSlowInEasing

代码语言:javascript
复制
/**
 * 快速加速,逐渐减速
 */
val FastOutSlowInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)

/**
 * Incoming elements are animated using deceleration easing, which starts a transition
 * at peak velocity (the fastest point of an element’s movement) and ends at rest.
 *
 * This is equivalent to the Android `LinearOutSlowInInterpolator`
 */
val LinearOutSlowInEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f)

/**
 * Elements exiting a screen use acceleration easing, where they start at rest and
 * end at peak velocity.
 *
 * This is equivalent to the Android `FastOutLinearInInterpolator`
 */
val FastOutLinearInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f)

/**
 * It returns fraction unmodified. This is useful as a default value for
 * cases where a [Easing] is required but no actual easing is desired.
 */
val LinearEasing: Easing = Easing { fraction -> fraction }

Easing

FastOutSlowInEasing

LinearOutSlowInEasing

FastOutLinearInEasing

LinearEasing

3.keyframes

keyframes可以选择在不同的时段,手动控制值的变化,并可以使用with指定Easing

代码语言:javascript
复制
@Preview
@Composable
fun MyKeyframes() {
    var targetValue by remember { mutableStateOf(0.dp) }
    val paddingTop by animateDpAsState(
        targetValue = targetValue,
        animationSpec = keyframes {
            // 执行时长为1s
            durationMillis = 1000

            // 在200ms内,以LinearEasing达到目标值的1/4
            targetValue / 4 at 200 with LinearEasing
            // 在200ms - 500ms,以LinearOutSlowInEasing达到目标值的1 / 2
            targetValue / 2 at 500 with LinearOutSlowInEasing
            // 在500ms - 800ms,达到目标值的3 / 4
            targetValue * 3 / 4 at 800
            // 在900ms后到执行结束,达到目标值
            targetValue at 900
        }
    )

    Box(
        modifier = Modifier
            .padding(top = paddingTop)// 上边距随动画值而变化
            .width(50.dp)
            .height(50.dp)
            .background(Color.Blue)
            .clickable {
                targetValue = 300.dp
            }
    )
}

效果:

4.repeatable

repeatable可以为基于时长的动画(如tweenkeyframes)加上可以重复执行的效果,repeatMode 用来指定重复的模式:从头开始 (RepeatMode.Restart) , 从结尾开始 (RepeatMode.Reverse)

代码语言:javascript
复制
@Preview
@Composable
fun MyRepeatable() {
    var targetValue by remember { mutableStateOf(0.dp) }
    val paddingTop by animateDpAsState(
        targetValue = targetValue,
        animationSpec = repeatable(
            iterations = 3,
            animation = tween(2000, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        )
    )

    Box(
        modifier = Modifier
            .padding(top = paddingTop)// 上边距随动画值而变化
            .width(50.dp)
            .height(50.dp)
            .background(Color.Blue)
            .clickable {
                targetValue = 100.dp
            }
    )
}

效果:

5.infiniteRepeatable

infiniteRepeatable为无限循环执行的动画

6.snap

snap会立即将值切换到结束值,您可以指定 delayMillis 来延迟动画播放的开始时间

代码语言:javascript
复制
@Preview
@Composable
fun MySnap() {
    var targetValue by remember { mutableStateOf(0.dp) }
    val paddingTop by animateDpAsState(
        targetValue = targetValue,
        animationSpec = snap(
            delayMillis = 50
        )
    )

    Box(
        modifier = Modifier
            .padding(top = paddingTop)// 上边距随动画值而变化
            .width(50.dp)
            .height(50.dp)
            .background(Color.Blue)
            .clickable {
                targetValue = 100.dp
            }
    )
}

效果:

二、高级动画

高级动画就是compose专门迎合MD风格封装的动画,也足够我们在日常开发中使用了

1.AnimatedVisibility

前面我们已经使用过该组件了,AnimatedVisibility可为内容的出现和消失添加动画效果,默认为所有内容组件添加以淡入和扩大的方式出现,以淡出和缩小的方式消失

1.1 基本使用

直接上代码:

代码语言:javascript
复制
@Preview
@Composable
fun MyAnimeVisible() {
    var visible by remember { mutableStateOf(false) }

    Row {
        AnimatedVisibility(visible = visible) {
            Icon(Icons.Rounded.Build, contentDescription = null)
        }

        Button(onClick = { visible = !visible }) {
            Text("click")
        }
    }
}

效果:

1.2 EnterTransition&ExitTransition

也可以通过给AnimatedVisibility指定 EnterTransitionExitTransition 来自定义这种过渡效果, EnterTransitionExitTransition 都支持了运算符重载,可以方便的组合各个过渡效果:

代码语言:javascript
复制
@Preview
@Composable
fun MyAnimeVisible2() {
    var visible by remember { mutableStateOf(false) }
    val density = LocalDensity.current

    Row {
        AnimatedVisibility(
            visible = visible,
            enter = slideInVertically {
                // Slide in from 40 dp from the top.
                with(density) { -40.dp.roundToPx() }
            } + expandVertically(
                // Expand from the top.
                expandFrom = Alignment.Top
            ) + fadeIn(
                // Fade in with the initial alpha of 0.3f.
                initialAlpha = 0.3f
            ),
            exit = slideOutVertically() + shrinkVertically() + fadeOut()
        ) {
            Icon(Icons.Rounded.Build, contentDescription = null)
        }

        Button(onClick = { visible = !visible }) {
            Text("click")
        }
    }
}

效果:

官网给出的各个效果图示如下:

EnterTransition

ExitTransition

fadeIn 淡入动画

fadeOut 淡出动画

slideIn 滑入动画

slideOut 滑出动画

slideInHorizontally 水平滑入动画

slideOutHorizontally 水平滑出动画

slideInVertically 垂直滑入动画

slideOutVertically 垂直滑出动画

scaleIn 缩放进入动画

scaleOut 缩放退出动画

expandIn 展开进入动画

shrinkOut 缩小退出动画

expandHorizontally 水平展开动画

shrinkHorizontally 水平缩小动画

expandVertically 垂直展开动画

shrinkVertically 垂直缩小动画

我们还可以通过它们的animationSpec属性,改变动画的执行过程,如执行时间、运动轨迹等

1.3 animateEnterExit修饰

此外,除了指定全体内容组件外,还记得在Modifier中可以使用animateEnterExit修饰来指定特定的内容组件的出现和消失动画吗?这种方式会和AnimatedVisibility中的动画进行组合,如果你不想要AnimatedVisibility中的默认动画效果,可以指定为 EnterTransition.NoneExitTransition.None

代码语言:javascript
复制
@OptIn(ExperimentalAnimationApi::class)
@Preview
@Composable
fun MyAnimeVisible3() {
    var visible by remember { mutableStateOf(false) }

    Row {
        AnimatedVisibility(
            visible = visible,
            enter = EnterTransition.None,//去除默认动画效果
            exit = ExitTransition.None
        ) {
            Column {
                Icon(Icons.Rounded.Build, contentDescription = null)
                Icon(
                    Icons.Rounded.Favorite, contentDescription = null,
                    // 单独使用特定的动画
                    modifier = Modifier.animateEnterExit(
                        enter = scaleIn(),
                        exit = scaleOut()
                    )
                )
            }
        }

        Button(onClick = { visible = !visible }) {
            Text("click")
        }
    }
}

效果:

1.4 transition

AnimatedVisibilityScope中可以通过transition创建自定义的动画效果:

例子,给Box设置背景颜色变化的动画:

代码语言:javascript
复制
@OptIn(ExperimentalAnimationApi::class)
@Preview
@Composable
fun MyAnimeVisible5() {
    var visible by remember { mutableStateOf(false) }

    Row {
        AnimatedVisibility(
            visible = visible,
            enter = EnterTransition.None,//去除默认动画效果
            exit = ExitTransition.None
        ) {
            val bg by transition.animateColor { state ->
                if (state == EnterExitState.Visible) Color.Blue else Color.Gray
            }

            Box(
                modifier = Modifier
                    .size(50.dp)
                    .background(bg)
            )
        }

        Button(onClick = { visible = !visible }) {
            Text("click")
        }
    }
}

效果:

2.animate*AsState

通过animate*AsState,可以创建简单的动画:

例子:

代码语言:javascript
复制
@Preview
@Composable
fun MyAnimateState() {
    var enabled by remember { mutableStateOf(true) }
    val alpha: Float by animateFloatAsState(if (enabled) 1f else 0.5f)

    Row {
        Box(
            Modifier
                .size(50.dp)
                .graphicsLayer(alpha = alpha)
                .background(Color.Red)
        )

        Button(onClick = { enabled = !enabled }) {
            Text("click")
        }
    }
}

效果:

3.AnimatedContent

AnimatedContent需要绑定State状态,当状态发生改变,导致重组时,会为内容添加动画

3.1 基本使用
代码语言:javascript
复制
@OptIn(ExperimentalAnimationApi::class)
@Preview
@Composable
fun MyAnimatedContentPreview() {
    Row {
        var count by remember { mutableStateOf(0) }
        Button(onClick = { count++ }) {
            Text("Add")
        }
        
        AnimatedContent(targetState = count) { targetCount ->
            // Make sure to use `targetCount`, not `count`.
            Text(text = "Count: $targetCount")
        }
    }
}

效果:

3.2 transitionSpec

transitionSpec,可以指定内容显示和消失的动画,使用with将显示和消失动画进行结合

代码语言:javascript
复制
@OptIn(ExperimentalAnimationApi::class)
@Preview
@Composable
fun MyAnimatedContentPreview2() {
    Row {
        var count by remember { mutableStateOf(0) }
        Button(onClick = { count++ }) {
            Text("Add")
        }

        AnimatedContent(
            targetState = count,
            transitionSpec = {
                if (targetState >  5) {//如果大于5
                    // 从上到下滑入滑出,淡入淡出
                    slideInVertically { height -> height } + fadeIn() with
                            slideOutVertically { height -> -height } + fadeOut()
                } else {
                    // 从下到上滑入滑出,淡入淡出
                    slideInVertically { height -> -height } + fadeIn() with
                            slideOutVertically { height -> height } + fadeOut()
                }.using(
                    // 禁用裁剪、因为滑入滑出应该显示超出界限
                    SizeTransform(clip = false)
                )
            }
        ) { targetCount ->
            Text(text = "Count: $targetCount")
        }
    }
}

效果:

3.3 SizeTransform

SizeTransform可以更自由的在AnimatedContent执行时穿插动画效果:

代码语言:javascript
复制
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterial3Api::class)
@Preview
@Composable
fun MySizeTransformPreview() {
    var expanded by remember { mutableStateOf(false) }
    
    Surface(
        color = MaterialTheme.colorScheme.primary,
        onClick = { expanded = !expanded }
    ) {
        AnimatedContent(
            targetState = expanded,
            transitionSpec = {
                fadeIn(animationSpec = tween(150, 150)) with
                        fadeOut(animationSpec = tween(150)) using
                        SizeTransform { initialSize, targetSize ->
                            if (targetState) {// 如果展开
                                keyframes {
                                    // 在150ms内,先将宽度渐渐变为targetSize.width
                                    IntSize(targetSize.width, initialSize.height) at 150
                                    // 执行总时长1s
                                    durationMillis = 1000
                                }
                            } else {
                                keyframes {
                                    // 在150ms内,先将高度渐渐变为targetSize.width
                                    IntSize(initialSize.width, targetSize.height) at 150
                                    // 执行总时长1s
                                    durationMillis = 1000
                                }
                            }
                        }
            }
        ) { targetExpanded ->
            if (targetExpanded) {
                Expanded()
            } else {
                ContentIcon()
            }
        }
    }
}

@Composable
fun Expanded() {
    Box(contentAlignment = Alignment.Center) {
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_background),
            contentDescription = null,
            modifier = Modifier.matchParentSize(),
            contentScale = ContentScale.FillBounds
        )
        Text(
            "hi,This creates a SizeTransform with the provided clip \n" +
                    "and sizeAnimationSpec. By default, clip will be true. \n" +
                    "This means during the size animation, the content will be clipped to the animated size.\n" +
                    " sizeAnimationSpec defaults to return a spring animation."
        )
    }
}

@Composable
fun ContentIcon() {
    Box(contentAlignment = Alignment.Center) {
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_background),
            contentDescription = null,
            modifier = Modifier.matchParentSize(),
            contentScale = ContentScale.FillBounds
        )
        Icon(Icons.Rounded.Call, contentDescription = null)
    }
}

效果:

4.animateContentSize修饰

animateContentSize修饰会在内容大小发生变化时,有一个动画效果,直接变化会导致显得突兀:

代码语言:javascript
复制
@Preview
@Composable
fun MyAnimateContentSizePreview() {
    val textArr = arrayOf("hello", "hi", "hello world")
    var textPosition by remember { mutableStateOf(0) }

    Column {
        Box(
            modifier = Modifier
                .background(MaterialTheme.colorScheme.primary)
                .animateContentSize()
                .padding(10.dp)
        ) {
            Text(textArr[textPosition], color = MaterialTheme.colorScheme.onPrimary)
        }

        Button(onClick = { textPosition = Random.nextInt(textArr.size) }) {
            Text(text = "点我", color = MaterialTheme.colorScheme.onPrimary)
        }
    }
}

效果:

5.Crossfade

Crossfade会在内容组件重组时,有一个淡入淡出的动画效果:

代码语言:javascript
复制
@Preview
@Composable
fun MyCrossfade() {
    var currentPage by remember { mutableStateOf("A") }

    Column() {
        Crossfade(targetState = currentPage) { screen ->
            when (screen) {
                "A" -> Text(
                    text = "Page A",
                    modifier = Modifier
                        .background(MaterialTheme.colorScheme.surface)
                        .padding(10.dp),
                    color = MaterialTheme.colorScheme.onSurface
                )
                "B" -> Text(
                    text = "Page B",
                    modifier = Modifier
                        .background(MaterialTheme.colorScheme.error)
                        .padding(10.dp),
                    color = MaterialTheme.colorScheme.onError
                )
            }
        }

        Button(onClick = {
            if (currentPage == "A") {
                currentPage = "B"
            } else {
                currentPage = "A"
            }
        }) {
            Text("click")
        }
    }
}

效果:

6.Transition

AnimatedVisibilityScope中可以直接获取到transition进而自定义一些动画,该对象为Transition,可管理一个或多个动画作为其子项,并在多个状态之间同时运行这些动画,通过Transition也可以直接使用AnimatedVisibilityAnimatedContent

6.1 基本使用updateTransition

通过updateTransition获取一个Transition对象,结合状态定义动画效果:

代码语言:javascript
复制
@Preview
@Composable
fun MyTransition() {
    var currentState by remember { mutableStateOf(MyState.Normal) }
    // 定义Transition对象
    val transition = updateTransition(currentState)

    // 根据状态改变边框线宽度
    val borderWidth by transition.animateDp { state ->
        when (state) {
            MyState.Normal -> Dp.Hairline
            MyState.Expand -> 1.dp
        }
    }

    Column(
        Modifier
            .background(MaterialTheme.colorScheme.surface)
            .border(borderWidth, MaterialTheme.colorScheme.outline)
            .padding(10.dp)
    ) {
        Button(onClick = {
            currentState = if (currentState == MyState.Normal) {
                MyState.Expand
            } else {
                MyState.Normal
            }
        }) {
            Text("click")
        }
    }
}

效果:

6.2 transitionSpec

AnimatedContenttransitionSpec类似,TransitiontransitionSpec可以为过渡状态变化的指定不同的AnimationSpecAnimationSpec可以用于改变动画的执行过程,在传统安卓开发中,我们称之为插值器:

代码语言:javascript
复制
@Preview
@Composable
fun MyTransition2() {
    var currentState by remember { mutableStateOf(MyState.Normal) }
    // 定义Transition对象
    val transition = updateTransition(currentState)
    val contentWidth = 100.dp
    val contentHeight = 50.dp

    // 根据状态改变边框线左边坐标
    val offsetLeft by transition.animateDp(transitionSpec = {
        when {
            MyState.Normal isTransitioningTo MyState.Expand ->// 当从MyState.Normal到MyState.Expand的过程
                // 弹性动画,移动的较慢
                spring(stiffness = Spring.StiffnessVeryLow)
            else ->
                // 指定动画的执行事件,移动的较快
                spring(stiffness = Spring.StiffnessMedium)
        }
    }) { state ->
        // 从 0 到 contentWidth
        when (state) {
            MyState.Normal -> 0.dp
            MyState.Expand -> contentWidth
        }
    }

    // 根据状态改变边框线右边边坐标
    // 右边的transitionSpec和左边相反
    val offsetRight by transition.animateDp(transitionSpec = {
        when {
            MyState.Normal isTransitioningTo MyState.Expand ->// 当从MyState.Normal到MyState.Expand的过程
                // 弹性动画,移动的较快
                spring(stiffness = Spring.StiffnessMedium)
            else ->
                // 指定动画的执行事件,移动的较慢
                spring(stiffness = Spring.StiffnessVeryLow)
        }
    }) { state ->
        // 从 contentWidth 到 contentWidth*2
        when (state) {
            MyState.Normal -> contentWidth
            MyState.Expand -> contentWidth * 2
        }
    }

    // 根据状态改变边框颜色
    val color by transition.animateColor { state ->
        when (state) {
            MyState.Normal -> Color.Red
            MyState.Expand -> Color.Green
        }
    }

    ConstraintLayout(
        Modifier
            .background(MaterialTheme.colorScheme.surface)
            .padding(5.dp)
    ) {
        val (row, box, btn) = createRefs()

        Row(
            modifier = Modifier.constrainAs(row) {
                top.linkTo(parent.top)
            }
        ) {
            androidx.compose.material.Text(
                "normal", modifier = Modifier
                    .size(contentWidth, contentHeight),
                textAlign = TextAlign.Center
            )
            androidx.compose.material.Text(
                "expand", modifier = Modifier
                    .size(contentWidth, contentHeight),
                textAlign = TextAlign.Center
            )
        }

        Box(
            modifier = Modifier
                .constrainAs(box) {
                    top.linkTo(row.top)
                }
                .offset(x = offsetLeft)
                .height(contentHeight)
                .width(offsetRight - offsetLeft)
                .fillMaxSize()
                .border(BorderStroke(1.dp, color), RoundedCornerShape(4.dp))
        )

        Button(
            modifier = Modifier.constrainAs(btn) {
                top.linkTo(box.bottom)
            }, onClick = {
                currentState = if (currentState == MyState.Normal) {
                    MyState.Expand
                } else {
                    MyState.Normal
                }
            }) {
            Text("click")
        }
    }
}

效果:

访问.gif

6.3 createChildTransition

Transition还可以通过createChildTransition()方法创建新的子Transition,当需要分离多个子组件用到的过渡时,可以通过该方式

代码语言:javascript
复制
@OptIn(ExperimentalTransitionApi::class)
@Preview
@Composable
fun MyTransition3() {
    var currentState by remember { mutableStateOf(MyState.Normal) }
    // 定义Transition对象
    val transition = updateTransition(currentState)

    val childTransitionState = transition.createChildTransition {
        MyState.Expand
    }

    val childTransitionBool = transition.createChildTransition {
        it == MyState.Expand
    }
}
6.4 rememberInfiniteTransition

rememberInfiniteTransition可以生成一个一直运行的Transition,方法和一般的Transition相同,使用时需要指定infiniteRepeatable

代码语言:javascript
复制
@Preview
@Composable
fun MyRememberInfiniteTransition() {
    val transition = rememberInfiniteTransition()

    val animateColor by transition.animateColor(
        initialValue = Color.Red,
        targetValue = Color.Green,
        animationSpec = infiniteRepeatable(
            animation = tween(1000),
            repeatMode = RepeatMode.Reverse
        )
    )

    Box(
        Modifier
            .background(animateColor, MaterialTheme.shapes.medium)
            .size(50.dp))
}

效果:

三、低级动画

关于低级动画的介绍可以查看官方文档:低级别动画 高级动画已经和compose进行了结合,而低级动画都是基于协程的API,也就是在使用过程中,我们需要手动启动协程,我们可以使用附带效应的LaunchedEffect()compose中启动一个协程,关于附带效应后续会详细介绍

1.Animation

Animation 是可用的最低级别的动画API,子类型有两种:TargetBasedAnimationDecayAnimation。除非你需要手动控制动画时间,否则建议使用基于这些类构建的更高级别动画 API,由于平时基本不会使用,这部分仅作了解即可

1.1 TargetBasedAnimation

TargetBasedAnimation 就是正常的执行动画,需要手动根据执行的时间获取动画值:

代码语言:javascript
复制
@Preview
@Composable
fun MyAnimation() {
    val basedAnimation = remember {
        TargetBasedAnimation(
            // 动画时间1s
            animationSpec = infiniteRepeatable(tween(1000)),
            // 值为float类型
            typeConverter = Float.VectorConverter,
            // 初始值200f
            initialValue = 200f,
            // 目标值400f
            targetValue = 400f,
        )
    }

    var width by remember {
        mutableStateOf(0.dp)
    }

    LaunchedEffect(basedAnimation) {
        val startTime = withFrameNanos { it }
        var playTime = 0L

        while (true) {
            playTime = withFrameNanos { it } - startTime

            width = Dp(basedAnimation.getValueFromNanos(playTime))
        }
    }

    Box(
        modifier = Modifier
            .width(width)// 宽度随动画值而变化
            .height(50.dp)
            .background(Color.Blue)
    )
}

效果:

1.2 DecayAnimation

DecayAnimation是执行动画过程会有衰减,下面会在Animatable中使用它

2.Animatable

Animatable为 Float 和 Color 提供开箱即用的支持,也可以通过TwoWayConverter对其他类型支持

2.1 基本使用
代码语言:javascript
复制
@Preview
@Composable
fun MyAnimatable() {
    val animatable = remember { Animatable(Color.Gray) }

    var ok by remember { mutableStateOf(false) }
    LaunchedEffect(ok) {
        animatable.animateTo(if (ok) Color.Green else Color.Red)
    }

    Box(
        modifier = Modifier
            .background(animatable.value)
            .size(50.dp)
            .clickable {
                ok = !ok
            }
    )
}

效果:

2.2 animateDecay

animateDecayDecayAnimation进行了封装,我们需要传入初始速度initialVelocity,以及对应的DecayAnimationSpecDecayAnimationSpec直接通过封装好的rememberSplineBasedDecay()获取即可

代码语言:javascript
复制
    suspend fun animateDecay(
        initialVelocity: T,// 初始速度
        animationSpec: DecayAnimationSpec<T>,// 衰减,估值器
        block: (Animatable<T, V>.() -> Unit)? = null
    )
代码语言:javascript
复制
@Preview
@Composable
fun MyDecayAnimation() {
    val anim = remember { Animatable(0.dp, Dp.VectorConverter) }
    val decaySpec = rememberSplineBasedDecay<Dp>()

    LaunchedEffect(anim) {
        delay(3000)
        anim.animateDecay(1000.dp, decaySpec)
    }

    Box(
        modifier = Modifier
            .padding(top = anim.value)// 上边距随动画值而变化
            .width(50.dp)
            .height(50.dp)
            .background(Color.Blue)
    )
}

效果:

2.3 exponentialDecay

exponentialDecay以指数进行衰减,可以传入摩擦系数:

代码语言:javascript
复制
@Preview
@Composable
fun MyDecayAnimation() {
    val anim = remember { Animatable(0.dp, Dp.VectorConverter) }
    // val decaySpec = rememberSplineBasedDecay<Dp>()
    val exponentDecay = exponentialDecay<Dp>(frictionMultiplier = 0.9f)

    LaunchedEffect(anim) {
        delay(3000)
        anim.animateDecay(1000.dp, exponentDecay)
    }

    Box(
        modifier = Modifier
            .padding(top = anim.value)// 上边距随动画值而变化
            .width(50.dp)
            .height(50.dp)
            .background(Color.Blue)
    )
}

效果:

四、可绘制图形动画

1.Drawable动画

就是传统通过定义xml的方式的帧动画

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:drawable="@drawable/ic_launcher_foreground"
        android:duration="100" />
    <item
        android:drawable="@drawable/ic_launcher_background"
        android:duration="100" />
</animation-list>
2.矢量图动画

矢量图动画可以参考官方文档:矢量图动画

由于需要配合SVG图片,这边不做展示

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-12-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、AnimationSpec
    • 1.spring
      • 2.tween
        • 2.1 基本使用
        • 2.2 easing
      • 3.keyframes
        • 4.repeatable
          • 5.infiniteRepeatable
            • 6.snap
            • 二、高级动画
              • 1.AnimatedVisibility
                • 1.1 基本使用
                • 1.2 EnterTransition&ExitTransition
                • 1.3 animateEnterExit修饰
                • 1.4 transition
              • 2.animate*AsState
                • 3.AnimatedContent
                  • 3.1 基本使用
                  • 3.2 transitionSpec
                  • 3.3 SizeTransform
                • 4.animateContentSize修饰
                  • 5.Crossfade
                    • 6.Transition
                      • 6.1 基本使用updateTransition
                      • 6.2 transitionSpec
                      • 6.3 createChildTransition
                      • 6.4 rememberInfiniteTransition
                  • 三、低级动画
                    • 1.Animation
                      • 1.1 TargetBasedAnimation
                      • 1.2 DecayAnimation
                    • 2.Animatable
                      • 2.1 基本使用
                      • 2.2 animateDecay
                      • 2.3 exponentialDecay
                  • 四、可绘制图形动画
                    • 1.Drawable动画
                      • 2.矢量图动画
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档