点击查看:Jetpack Compose 教程
点击查看:Composetutorial 代码
简介
Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API,可以帮助您简化并加快 Android 界面开发。
在本教程中,您将使用声明性的函数构建一个简单的界面组件。您无需修改任何 XML 布局,也不需要使用布局编辑器。相反,您只需调用可组合函数来定义所需的元素,Compose 编译器即会完成后面的所有工作。
列表和动画
列表和动画在应用内随处可见。在本课中,您将学习如何利用 Compose 轻松创建列表并添加有趣的动画效果。
效果图
创建消息列表
只包含一条消息的聊天略显孤单,因此我们将更改对话,使其包含多条消息。您需要创建一个可显示多条消息的 Conversation 函数。对于此用例,请使用 Compose 的 LazyColumn 和 LazyRow。这些可组合项只会呈现屏幕上显示的元素,因此,对于较长的列表,使用它们会非常高效。
在此代码段中,您可以看到 LazyColumn 包含一个 items 子项。它接受 List 作为参数,并且其 lambda 会收到我们命名为 message 的参数(可以随意为其命名),该参数是 Message 的实例。简而言之,系统会针对提供的 List 的每个项调用此 lambda。将示例数据集复制到您的项目中,以便快速引导对话。
在展开消息时显示动画效果
对话变得更加有趣了。是时候添加动画效果了!您将添加展开消息以显示更多内容的功能,同时为内容大小和背景颜色添加动画效果。为了存储此本地界面状态,您需要跟踪消息是否已展开。为了跟踪这种状态变化,您必须使用 remember 和 mutableStateOf 函数。
可组合函数可以使用 remember 将本地状态存储在内存中,并跟踪传递给 mutableStateOf 的值的变化。该值更新时,系统会自动重新绘制使用此状态的可组合项(及其子项)。这称为重组。
通过使用 Compose 的状态 API(如 remember 和 mutableStateOf),系统会在状态发生任何变化时自动更新界面。
注意: 您需要添加以下导入内容才能正确使用 Kotlin 的委托属性语法(by 关键字)。按 Alt+Enter 键或 Option+Enter 键即可添加这些内容。
import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue
现在,您可以根据点击消息时消息的 isExpanded 状态,更改消息内容的背景颜色。您将使用 clickable 修饰符来处理可组合项上的点击事件。您会为背景颜色添加动画效果,使其值逐步从 MaterialTheme.colorScheme.surface 更改为 MaterialTheme.colorScheme.primary(反之亦然),而不只是切换 Surface 的背景颜色。为此,您将使用 animateColorAsState 函数。最后,您将使用 animateContentSize 修饰符顺畅地为消息容器大小添加动画效果:
Base04.kt代码
package com.example.composetutorial.activity
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.example.composetutorial.R
import com.example.composetutorial.ui.theme.ComposeTutorialTheme
/*
https://developer.android.google.cn/jetpack/compose/tutorial
第 4 课:列表和动画
创建消息列表
只包含一条消息的聊天会略显孤单,因此请更改对话,使其包含多条消息。您需要创建一个可显示多条消息的 Conversation 函数。对于此用例,请使用 Compose 的 LazyColumn 和 LazyRow。这些可组合项只会呈现屏幕上显示的元素,因此,对于较长的列表,使用它们会非常高效。
在此代码段中,您可以看到 LazyColumn 包含一个 items 子项。它接受 List 作为参数,并且其 lambda 会收到我们命名为 message 的参数(可以随意为其命名),它是 Message 的实例。简而言之,系统会针对提供的 List 的每个项调用此 lambda。将此示例数据集导入您的项目,以便快速引导对话。
在展开消息时显示动画效果
对话变得更加有趣了。是时候添加动画效果了!您将添加展开消息以显示更多内容的功能,同时为内容大小和背景颜色添加动画效果。为了存储此本地界面状态,您需要跟踪消息是否已展开。为了跟踪这种状态变化,您必须使用 remember 和 mutableStateOf 函数。
可组合函数可以使用 remember 将本地状态存储在内存中,并跟踪传递给 mutableStateOf 的值的变化。该值更新时,系统会自动重新绘制使用此状态的可组合项(及其子项)。这称为重组。
通过使用 Compose 的状态 API(如 remember 和 mutableStateOf),系统会在状态发生任何变化时自动更新界面。
注意:您需要添加以下导入内容才能正确使用 by。按 Alt+Enter 键或 Option+Enter 键即可添加这些内容。
import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue
现在,您可以根据 isExpanded 更改点击消息时的消息内容的背景。您将使用 clickable 修饰符来处理可组合项上的点击事件。您会为背景颜色添加动画效果,使其值逐步从 MaterialTheme.colors.surface 更改为 MaterialTheme.colors.primary(反之亦然),而不只是切换 Surface 的背景颜色。为此,您将使用 animateColorAsState 函数。最后,您将使用 animateContentSize 修饰符顺畅地为消息容器大小添加动画效果:
*/
class Base04 :ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeTutorialTheme {
val msgs = mutableListOf<Message4>()
for (index in 0 .. 30){
msgs.add(Message4("Test ${index}","描述内容 ${index} import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue 现在,您可以根据 isExpanded 更改点击消息时的消息内容的背景。您将使用 clickable 修饰符来处理可组合项上的点击事件。您会为背景颜色添加动画效果"))
}
Conversation(msgs)
}
}
}
}
data class Message4(val author: String, val body: String)
@Composable
fun MessageCard(msg: Message4) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.mipmap.icon_nav_mine),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colors.secondaryVariant, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
// We keep track if the message is expanded or not in this
// variable
var isExpanded by remember { mutableStateOf(false) }
// We toggle the isExpanded variable when we click on this Column
Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
Text(
text = msg.author,
color = MaterialTheme.colors.secondaryVariant,
style = MaterialTheme.typography.subtitle2
)
Spacer(modifier = Modifier.height(4.dp))
Surface(
shape = MaterialTheme.shapes.medium,
elevation = 1.dp,
) {
Text(
text = msg.body,
modifier = Modifier.padding(all = 4.dp),
// If the message is expanded, we display all its content
// otherwise we only display the first line
maxLines = if (isExpanded) Int.MAX_VALUE else 1,
style = MaterialTheme.typography.body2
)
}
}
}
}
@Composable
fun Conversation(messages: List<Message4>) {
LazyColumn {
items(messages) { message ->
MessageCard(message)
}
}
}
欢迎关注我的公众号,不定期推送优质的文章,
微信扫一扫下方二维码即可关注。