本系列是我学习compose过程中,对官方文档的翻译和解读,以及实验性的Demo工程。主要参考官方文档和中文手册
全部的正文内容(Demo工程除外)源自Compose官方文档,个人解读以引用的形式插入。
Compose 官方文档 https://developer.android.google.cn/jetpack/compose
Compose 中文手册 https://compose.net.cn/
本文翻译内容 https://developer.android.google.cn/jetpack/compose/state
App
中的状态是指任何可以随着时间改变的值。这是个非常宽泛的概念,包含了几乎所有东西,大到一个Room
数据库,小到某个类的一个成员变量
所有的Android应用都是在把状态展示给用户。下面是一些例子
- 无网络连接时展示的
snackBar
- A blog post and associated comments.
- 用户点击按钮时触发的涟漪动画
- 用户在图像上绘制的贴纸
Jetpack Compose 能帮助你明确在哪里存放这些状态,以及如何使用它们。本文主要关心状态与可组合函数之间的关系,以及Jetpack Compose提供了一些帮助你管理状态的API。
状态与绘制
Compose是声明式的,所以想更改一个组件的状态,只能用新的状态值去调用该组件的可组合函数。这些状态值描述了这个UI
组件的状态。状态的更新就对应着重绘的发生。所以,当UI
的状态值改变时,基于XML的UI
框架会自动刷新UI
,但是在Compose中,必须显式地调用该UI
的可组合函数,才能刷新该UI
@Composable
fun HelloContent() {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = "",
onValueChange = {
},
label = {
Text("Name") }
)
}
}
运行上述代码,会发现虽然向输入框输入了文字,但并没有渲染出来。这是因为Compose的渲染机制决定,必需显式重新调用OutlinedTextField这个可组合函数,但显然这里并没有
这里的OutlinedTextField暂时理解成Compose版本的EditText
关键词解释:
Composition: Jetpack Compose把可组合函数渲染成
UI
的这个过程,可以意译成绘制Initial composition: 首次运行可组合函数进行的绘制过程
Recomposition: 当状态值改变后,再次调用可组合函数进行的绘制过程
可组合函数中的状态
通过remember
函数,可组合函数可以在内存中保存一个单例。第一次绘制时,通过remeber记录的值会被保存到这个单例中,再次绘制时,这个值会被返回。remember
可以用来存储可变或不可变的对象
注意: 当这个
UI
组件被从整个UI
树上移除时,remember
记录的这个单例会被回收
mutableStateOf
函数创建一个类型为 MutableState
的可观察对象
interface MutableState<T> : State<T> {
override var value: T
}
value
的改变会通知所有订阅了该可观察对象的可组合函数,并触发它们的重绘。
可组合函数中有三种方式定义一个 MutableState
对象
val mutableState = remember { mutableStateOf(default) }
var value by remember { mutableStateOf(default) }
val (value, setValue) = remember { mutableStateOf(default) }
这三种声明是等价的,选择一种对你来说最容易阅读的即可
注意使用by
委托的写法,需要这两个依赖
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
通过remember
保存的变量,不仅可以作为其他可组合函数的入参,还可以参与逻辑控制。例如下面对name
的非空判断
@Composable
fun HelloContent() {
Column(modifier = Modifier.padding(16.dp)) {
var name by remember {
mutableStateOf("") }
if (name.isNotEmpty()) {
Text(
text = "Hello, $name!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
}
OutlinedTextField(
value = name,
onValueChange = {
name = it },
label = {
Text("Name"