缘由

四点多刷的时候,看到这样一篇文章: 自定义View仿照立刻点赞数字切换作用,作者运用自定义制作的技术完成了数字切换的动态作用,也便是如图:

Jetpack Compose 十几行代码快速模仿即刻点赞数字切换效果

Jetpack Compose 十几行代码快速模仿即刻点赞数字切换效果

两图分别为立刻的作用和作者的完成

不得不说,作者仿照的很像,自定义制作玩的登峰造极,非常优异。不过,即使是这样简略的动效,运用 View 系统完成起来依然相对麻烦。对上文来说,作者运用的 Kotlin 代码也达到了约 170 行。

Composable

假如换成 Compose 呢?作为声明式框架,在处理这类动画上会不会有奇效?

答案是必定的!下面是最简略的完成:

Row(modifier = modifier) {
    text.forEach {
        AnimatedContent(
            targetState = it,
            transitionSpec = {
                slideIntoContainer(AnimatedContentScope.SlideDirection.Up) with
                        fadeOut() + slideOutOfContainer(AnimatedContentScope.SlideDirection.Up)
            }
        ) { char ->
            Text(text = char.toString(), modifier = modifier.padding(textPadding), fontSize = textSize, color = textColor)
        }
    }
}

你没看错,这便是 Composable 对应的简略仿照,中心代码不过十行。它的大致作用如下:

Jetpack Compose 十几行代码快速模仿即刻点赞数字切换效果

能看到,在数字改动时,相应的动画作用现已非常相似。当然他还有小瑕疵,比方在 99 – 100 时,最终一位的 0 没有初始动画;比方在数字减少时,他的动画方向应该相反。但这两个问题都是可以加点代码解决的,这里中心仅仅思路

原理

与上文作者将每个数字作为一个全体对待不同,我将每一位独立处理。观察图片,动画的中心在于每一位有差异时要做动画处理,因而将每一位独自处理能更好的树立状况。

Jetpack Compose 是声明式 UI,状况的改动自然而然就导致 UI 的改动,咱们所需求做的仅仅在 UI 改动时加个动画就可以。而刚好,关于这种内容的改动,Compose 为咱们提供了开箱即用的微件:AnimatedContent

AnimatedContent

此 Composable 签名如下:

@Composable
fun <S> AnimatedContent(
    targetState: S,
    modifier: Modifier = Modifier,
    transitionSpec: AnimatedContentScope<S>.() -> ContentTransform = {
        ...
    },
    contentAlignment: Alignment = Alignment.TopStart,
    content: @Composable() AnimatedVisibilityScope.(targetState: S) -> Unit
)

要点在于 targetState,在 content 内部,咱们需求获取到用到这个值,依据值的不同,呈现不同的 UI。AnimatedContent 会在 targetState 改动使自动对上一个 Composable 履行退出动画,并对新 Composable 履行进入动画 (有点幻灯片切换的感觉hh),在这里,咱们的动画是这样的:

slideIntoContainer(AnimatedContentScope.SlideDirection.Up)
with
fadeOut() + slideOutOfContainer(AnimatedContentScope.SlideDirection.Up)

上半部分的 slideIntoContainer 会履行进入动画,方向为自下向上;后半部分则是退出动画,由向上的路径动画和淡出结合而来。中缀函数 with 衔接它们。这也体现了 Kotlin 作为一门现代化语言的优雅。

关于 Compose 的更多常识,可以参阅 Compose 中文社区的大佬们一起维护的 Jetpack Compose 博物馆。

代码

本文的所有代码如下:

import androidx.compose.animation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun NumberChangeAnimationText(
    modifier: Modifier = Modifier,
    text: String,
    textPadding: PaddingValues = PaddingValues(horizontal = 8.dp, vertical = 12.dp),
    textSize: TextUnit = 24.sp,
    textColor: Color = Color.Black
) {
    Row(modifier = modifier) {
        text.forEach {
            AnimatedContent(
                targetState = it,
                transitionSpec = {
                    slideIntoContainer(AnimatedContentScope.SlideDirection.Up) with
                            fadeOut() + slideOutOfContainer(AnimatedContentScope.SlideDirection.Up)
                }
            ) { char ->
                Text(text = char.toString(), modifier = modifier.padding(textPadding), fontSize = textSize, color = textColor)
            }
        }
    }
}
@Composable
fun NumberChangeAnimationTextTest() {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        var text by remember { mutableStateOf("103") }
        NumberChangeAnimationText(text = text)
        Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
            // 加一 和 减一
            listOf(1, -1).forEach { i ->
                TextButton(onClick = {
                    text = (text.toInt() + i).toString()
                }) {
                    Text(text = if (i == 1) "加一" else "减一")
                }
            }
        }
    }
}

这个示例也被录入到了我的 JetpackComposeStudy: 自己 Jetpack Compose 主题文章所包含的示例,包括自定义布局、部分组件用法等 里,感兴趣的可以去那里检查更多代码。

Jetpack Compose 十几行代码快速模仿即刻点赞数字切换效果

最近敞开了2022的年度人气创作者评选,假如您对我的文章认可的话,欢迎投给我宝贵的一票,感谢!本文有协助的话,也欢迎点赞沟通

(现在6点13分,连写代码加写文章共用了一个多小时,嗯,收工~)