这篇文章介绍一些Compose官方现已封装好的,能够开箱即用的动画API。

animateContentSize内容巨细动画

animateContentSize内容巨细动画用于修正组件的内容巨细时增加动画作用,常用场景为展示内容过多需求收起,点击后再将其显现完整。

fun Modifier.animateContentSize(
    animationSpec: FiniteAnimationSpec<IntSize> = spring(),
    finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null
): Modifier = composed(
    inspectorInfo = debugInspectorInfo {
        name = "animateContentSize"
        properties["animationSpec"] = animationSpec
        properties["finishedListener"] = finishedListener
    }
) {
    val scope = rememberCoroutineScope()
    val animModifier = remember(scope) {
        SizeAnimationModifier(animationSpec, scope)
    }
    animModifier.listener = finishedListener
    this.clipToBounds().then(animModifier)
}

animateContentSize为Modifier的扩展办法,因此只需求组件的modifier调用该办法,便可在该组件的内容进行变化重组的时候呈现该动画。

animateContentSize内含两个参数,都有默认值,第一个参数为animationSpec动画标准,默以为SpringSpec弹性动画,可自定义动画作用,第二个参数为动画完成时的监听,默以为空。 简略示例:

    var change by remember { mutableStateOf(false) }
    Column(modifier = Modifier.animateContentSize()) {
        Text(text = "点击改动内容巨细", modifier = Modifier.clickable { change = !change })
        if (change) {
            Text(
                text = "这是一个大方块",
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Gray),
            )
        }
    }

AnimatedVisibility可见性动画

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

AnimatedVisibility有6个参数,只要第一个和最终一个参数有必要填入,其他参数都有默认值。

  • visible:定义内容是否应该可见,true 为可见,false 为不行见。
  • modifier:修饰符,Compose里随处可见。
  • enter:内容可见时的动画,默以为fadeIn() + expandIn(),大致意思为淡入并扩展开。
  • exit:内容不行见时的动画,默以为shrinkOut() + fadeOut(),大致意思为缩小并淡出消失。
  • label:标签,用于区分不同动画。
  • content:增加可见性动画作用的组合项内容。

简略示例:

    var change by remember { mutableStateOf(false) }
    Column {
        Text(text = "点击改动可见性", modifier = Modifier.clickable { change = !change })
        AnimatedVisibility(visible = change) {
            Text(
                text = "这是一个大方块",
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Gray),
            )
        }
    }

当然可完全能够自定义可见/不行见时的动画作用:

    var change by remember { mutableStateOf(false) }
    Column {
        Text(text = "点击改动可见性", modifier = Modifier.clickable { change = !change })
        AnimatedVisibility(
            visible = change,
            enter = slideInVertically(
                initialOffsetY = { fullHeight -> -fullHeight },
                animationSpec = tween(durationMillis = 150, easing = LinearOutSlowInEasing)
            ),
            exit = slideOutVertically(
                targetOffsetY = { fullHeight -> -fullHeight },
                animationSpec = tween(durationMillis = 250, easing = FastOutSlowInEasing)
            )
        ) {
            Text(
                text = "这是一个大方块",
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Gray),
            )
        }
    }

animateValueAsState单一值特点动画

特点动画就是通过不断地修正特点值来完成的。animateValueAsState对恣意值的特点动画。官方提供了一整套的api来完成简略的单一值特点动画。

Compose开箱即用的动画API
实际运用的时候按需选择即可。

@Composable
fun animateDpAsState(
    targetValue: Dp,
    animationSpec: AnimationSpec<Dp> = dpDefaultSpring,
    label: String = "DpAnimation",
    finishedListener: ((Dp) -> Unit)? = null
): State<Dp> {
    return animateValueAsState(
        targetValue,
        Dp.VectorConverter,
        animationSpec,
        label = label,
        finishedListener = finishedListener
    )
}

以animateDpAsState为例,共4个参数,第一个为目标值,有必要填入,其他参数都有默认值,第二个参数为animationSpec动画标准,默以为SpringSpec弹性动画,可自定义动画作用,第三第四个参数前面呈现过,按字面意思也可理解就不细说了。整个动画会以当前值为开端值,传入的targetValue为完毕值,以animationSpec动画标准进行动画作用。

简略示例:

    var small by remember { mutableStateOf(true) }
    val size: Dp by animateDpAsState(
        targetValue = if (small) 40.dp else 100.dp
    )
    Column(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(onClick = { small = !small }) {
            Text(text = "改动方块巨细")
        }
        Box(
            modifier = Modifier
                .size(size)
                .background(Color.LightGray)
        )
    }

updateTransition多值动画

updateTransition能够保存一个或多个子动画,当状态发生改动时,多个动画同时进行。能够运用animate*扩展办法增加子动画。

简略示例:运用animateDp和 animateColor同时进行两个子动画

    var change by remember { mutableStateOf(false) }
    val transition = updateTransition(targetState = change, label = "多值动画")
    val offset by transition.animateDp(label = "") { change ->
        if (change) 50.dp else 0.dp
    }
    val background by transition.animateColor(label = "") { change ->
        if (change) Color.Gray else Color.Blue
    }
    Column(modifier = Modifier.fillMaxWidth()) {
        Text(text = "点击进行多个动画", modifier = Modifier.clickable { change = !change })
        Text(
            text = "这是一个大方块",
            modifier = Modifier
                .size(100.dp)
                .offset(x = offset)
                .background(background),
        )
    }

rememberInfiniteTransition无限重复动画

rememberInfiniteTransition能够进行无限重复动画,也相同能够保存一个或多个子动画,可是,这些动画一进入组合阶段就开端运转,除非被移除,否则不会中止,能够运用 animateColor、animatedFloat 或 animatedValue 增加子动画。

简略示例:运用animatedValue增加子动画改动巨细size,而且运用animatedFloat增加子动画改动巨细透明度alpha

    val infiniteTransition = rememberInfiniteTransition()
    val size by infiniteTransition.animateValue(
        initialValue = 100.dp,
        targetValue = 200.dp,
        typeConverter = TwoWayConverter({ AnimationVector1D(it.value) }, { it.value.dp }),
        animationSpec = infiniteRepeatable(
            animation = tween(1000, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        )
    )
    val alpha by infiniteTransition.animateFloat(
        initialValue = 0f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = tween(1000, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        )
    )
    Box(
        Modifier
            .size(size)
            .padding(20.dp)
            .alpha(alpha)
            .background(Color.Red)
    )

最终

最终,运用上面这些动画API能够达到一些简略的动画作用,但如果想要一些杂乱的自定义的动画作用,能够运用animationSpec这个参数,详细见Compose动画学习之AnimationSpec。