目录
创建一个列表消息卡片
到目前为止,我们只有一个消息的卡片,看上去有点单调,所以让我们来改善它,让它拥有多条信息。我们需要创建一个能够显示多条消息的函数。对于这种情况,我们可以使用 Compose 的 LazyColumn 和 LazyRow。这些 Composable 只渲染屏幕上可见的元素,所以它们的设计对于长列表来说很有效果。同时,它们避免了 RecyclerView 与 XML 布局的复杂性。
import androidx.compose.foundation.lazy.items @Composable fun Conversation(messages: List<Message>) { LazyColumn { items(messages) { message -> MessageCard(msg = message) } } } @Composable fun PreviewMessageCard() { ComposestudyTheme { Conversation(messages = MsgData.messages) } }
你可以在这里获取 MsgData
的代码
MsgData.kt
object MsgData { private const val author = "大前端之旅" val messages = listOf( Message(author, "我们开始更新啦"), Message(author, "秋刀鱼会过期吗?"), Message(author, "下周就是端午了"), Message(author, "男人最好的状态是,25岁的时候能带着30岁的成熟去经营爱情,30岁的时候还带着18岁的不怕,去勇敢爱\uD83D\uDCAA"), Message(author, "Android之旅"), ) }
在这个代码片段中,你可以看到 LazyColumn
有一个 items 子项。它接收一个 List 作为参数,它的 lambda 接收一个我们命名为 message 的参数(我们可以随便命名)。 而这个 lambda 将会调用每个 List 中里面提供的 item。
可交互的动画效果
我们的对话越来越有趣了,是时候玩玩动画了! 我们将会实现当点击一个卡片查看详细内容的时候,使内容的大小和背景颜色都有动画效果。为了存储这个本地 UI 状态,我们需要跟踪一条消息是否已经展开了。为了跟踪这种状态变化,我们必须使用 remember 和 mutableStateOf 函数。
Composable 函数可以通过使用 remember 将本地状态存储在内存中,并跟踪传递给 mutableStateOf 的值的变化。当值被更新时,使用该状态的 Composable 函数(及其子函数)将被自动重新绘制。我们把这称为重组(recomposition)。
通过使用 Compose 的状态 API,如 remember 和 mutableStateOf,任何对状态的改变都会自动更新 UI。
@Composable fun MessageCard(msg: Message) { var isExpanded by remember { mutableStateOf(false) } // 创建一个能够检测卡片是否被展开的变量 Surface( shape = MaterialTheme.shapes.medium, elevation = 5.dp, modifier = Modifier .padding(all = 8.dp) .clickable { // 添加一个新的 Modifier 扩展方法,可以让元素具有点击的效果 isExpanded = !isExpanded // 编写点击的事件内容 } ) { Row( modifier = Modifier.padding(all = 8.dp) ) { Image( painterResource(id = R.drawable.profile_picture), contentDescription = "profile picture", modifier = Modifier .size(50.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colors.secondary, shape = CircleShape) ) Spacer(Modifier.padding(horizontal = 8.dp)) Column { Text( text = msg.author, color = MaterialTheme.colors.secondaryVariant, style = MaterialTheme.typography.subtitle2 ) Spacer(Modifier.padding(vertical = 4.dp)) Text( text = msg.body, style = MaterialTheme.typography.body2, // 修改 maxLines 参数,在默认情况下,只显示一行文本内容 maxLines = if (isExpanded) Int.MAX_VALUE else 1, // Composable 大小的动画效果 modifier = Modifier.animateContentSize() ) } } } }
现在我们已经能够完成每个卡片的检测了,让我们继续使用 isExpanded
来做点其他的事情吧!比如改变卡片的颜色
// 创建一个能够根据 isExpanded 变量值而改变颜色的变量 val surfaceColor by animateColorAsState( targetValue = if (isExpanded) Color(0xFFCCCCCC) else MaterialTheme.colors.surface ) Surface( shape = MaterialTheme.shapes.medium, elevation = 5.dp, modifier = Modifier .padding(all = 8.dp) .clickable { isExpanded = !isExpanded }, color = surfaceColor ) { ... ... }