Android Compose 05 简单动画

前言

  在前一节中我们实现了点击消息框展开的功能,但是实现出来的效果较为生硬没有现代App所追求的丝滑的效果,本节中将会通过一些简单的动画将展开的效果完善。

Compose动画

  Compose为我们提供了许多开箱即用的动画实现方式以及部分可通过自定义实现的,本节只讨论一些简单的动画实现,具体的Compose动画内容将会在后面的章节讲解

  上一章节中折叠文本由于有省略,大部分的需求中都需要在不完整显示的文本后面加上省略号,在Compose中我们可以很简单的在Modifier中添加 overflow = TextOverflow.Ellipsis 来实现省略文本自动添加省略号的功能。效果如下:

  现在我们要实现展开后的消息背景颜色与原来的不一样且是渐变过去而非直接切换。Compose中提供了一系列的函数 animateXXXAsState 可以将一个值转为可观测的动画状态,我们现在要改变背景颜色只需要调用 animateColorAsState 即可。使用方法如下:

val textBgColor by animateColorAsState(
    targetValue = if (isExpanded) Color.Green else Color.Transparent,
    label = "textBgColor"
)

其中isExpanded是上一节中定义的关于收缩文本框是否处于扩张状态的变量,在 animateColorAsState 中我们只需要根据情况改变 targetValue 的值即可自动完成渐变转化的过程。之后我们只需要将 textBgColor 变量如Color一样使用即可。

  将生硬的展开动画转为动画也仅需要使用为 modifier 添加使用 animateContentSize() 函数即可,这个函数的作用是将改变的大小通过动画的方式呈现出来,当不需要关注变化的速度、变化的方向等因素时不需要向其中传入参数,采用默认的即可。

  我们只需要将上文中提到的参数放在一个包含消息文本的 Box 布局的 Modifier 参数当中即可。这时候我们运行检查效果会发现消息文本旁边的背景颜色所框出的区域是矩形的,不太符合现在的审美。只需要添加在第三章中学到的 clip 参数将背景设为圆角即可。完整代码如下:

@Composable
fun MessageCard(message: MessageData) {
    var isExpanded by remember { mutableStateOf(false) }
    val textBgColor by animateColorAsState(
        targetValue = if (isExpanded) Color.Green else Color.Transparent,
        label = "textBgColor"
    )
    Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = Modifier
            .padding(horizontal = 10.dp, vertical = 20.dp)
            .fillMaxWidth()
            .clickable { isExpanded = !isExpanded }
    ) {
        Image(
            painter = painterResource(id = R.drawable.melon),
            contentDescription = "icon",
            modifier = Modifier
                .size(80.dp)
                .clip(CircleShape)
        )
        Spacer(modifier = Modifier.width(10.dp))
        Column {
            Text(
                text = message.username,
                fontSize = 20.sp,
                color = Color.Black
            )
            Spacer(modifier = Modifier.height(10.dp))
            Box(
                modifier = Modifier
                    .clip(RoundedCornerShape(5.dp))
                    .background(textBgColor)
                    .animateContentSize()
                    .padding(5.dp)
            ) {
                Text(
                    text = message.message,
                    fontSize = 18.sp,
                    color = Color.Black,
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    overflow = TextOverflow.Ellipsis
                )
            }
        }
    }
}

需要注意的是 clip 方法必须放在 background 方法之上否则是没有效果的,不同于AndroidView系统中的控制样式的参数,modifier 中调用方法的顺序是影响实际的呈现效果的。

  例如在这次使用中我们可以这样简单的理解。先调用 background 方法是将原本矩形的区域改变为目标颜色,随后调用 clip 函数是将包裹区域即content的区域裁剪为圆角,并不影响原来已经更改颜色的区域,所以在视觉上看到染色的区域还是矩形的。

  相反,先调用 clip 限制区域,再调用background 方法改变区域颜色,改变颜色的区域就是被 clip 限制出来的区域了,在视觉效果上就是圆角了。上文代码具体效果如下:


初めて会ったの日から 僕の心の全てを奪った