状态 State
kotlin
// Don't copy over
@Composable
private fun Greeting(name: String) {
var expanded = false // Don't do this!
Surface(
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
) {
Row(modifier = Modifier.padding(24.dp)) {
Column(modifier = Modifier.weight(1f)) {
Text(text = "Hello, ")
Text(text = name)
}
ElevatedButton(
onClick = { expanded = !expanded }
) {
Text(if (expanded) "Show less" else "Show more")
}
}
}
}
通过点击 Button 切换按钮文本内容,定义了临时变量 expanded,点击时修改;这种写法在 Compose 无法发挥作用;
原因:普通变量 expanded
设置不同的值不会使 Compose 将其检测为状态更改,因此不会产生任何效果。
重组 :数据发生变化,Compose 会使用新数据重新执行这些函数,从而创建更新后的界面,此过程称为~
Compose 还会查看各个可组合项需要哪些数据,以便只需重组数据发生了变化的组件,而避免重组未受影响的组件。
State / MutableState
如需向可组合项添加内部状态,可以使用 mutableStateOf
函数,该函数可让 Compose 重组读取该 State
的函数。
State
和 MutableState
是两个接口,它们具有特定的值,每当该值发生变化时,它们就会触发界面更新(重组)。
解决:使用 mutableStateOf 后如下
kotlin
import androidx.compose.runtime.mutableStateOf
...
// Don't copy over
@Composable
fun Greeting() {
val expanded = mutableStateOf(false) // Don't do this!
Log.e("tag", "expanded = ${expanded.value}")
...
}
点击按钮后,触发了重组
,界面刷新了(log 会在点击按钮后打印),但按钮内容依然没变;
原因:每次调用 Greeting
时,都会将该变量重置为 false。
解决:如需在重组后保留状态,请使用 remember
记住可变状态。
Remember
remember
是记录数据,防止状态在重组时被重置;
至此:点击按钮变化文案的功能完毕了,修改后的代码如下
kotlin
@Composable
private fun Greeting(name: String) {
// 记录数据
val expanded = remember { mutableStateOf(false) }
Surface(
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
) {
Row(modifier = Modifier.padding(24.dp)) {
Column(modifier = Modifier.weight(1f)) {
Text(text = "Hello, ")
Text(text = name)
}
ElevatedButton(
onClick = { expanded.value = !expanded.value }
) {
Text(if (expanded.value) "Show less" else "Show more")
}
}
}
}
声明 MutableState 对象的三种方式:
val mutableState = remember { mutableStateOf(default) }
var value by remember { mutableStateOf(default) }
val (value, setValue) = remember { mutableStateOf(default) }
by
委托语法需要以下导入:
kotlinimport androidx.compose.runtime.getValue import androidx.compose.runtime.setValue
状态提升
无状态可组合项是指不保持任何状态的可组合项
Compose 中的状态提升是一种将状态移至可组合项的调用方以使可组合项无状态的模式
- 单一可信来源:通过移动状态,而不是复制状态,我们可确保只有一个可信来源。这有助于避免 bug。
- 封装:只有有状态可组合项能够修改其状态。这完全是内部的。
- 可共享 :可与多个可组合项共享提升的状态。如果您想在另一个可组合项中读取
name
,可以通过变量提升来做到这一点。 - 可拦截:无状态可组合项的调用方可以在更改状态之前决定忽略或修改事件。
- 解耦 :无状态
ExpandingCard
的状态可以存储在任何位置
kotlin
@Composable
fun HelloScreen() {
var name by rememberSaveable { mutableStateOf("") }
HelloContent(name = name, onNameChange = { name = it })
}
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, $name",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = name,
onValueChange = onNameChange,
label = { Text("Name") }
)
}
}
状态提升规则:
- 状态应至少提升到使用该状态(读取)的所有可组合项的最低共同父项。
- 状态应至少提升到它可以发生变化(写入)的最高级别。
- 如果两种状态发生变化以响应相同的事件 ,它们应一起提升。
LazyListState
官方文档解释: A state object that can be hoisted to control and observe scrolling.
文章参考:Compose 中的状态