Jetpack Compose 状态

状态 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 的函数。

StateMutableState 是两个接口,它们具有特定的值,每当该值发生变化时,它们就会触发界面更新(重组)。

解决:使用 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 委托语法需要以下导入:

kotlin 复制代码
import 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") }
        )
    }
}

状态提升规则:

  1. 状态应至少提升到使用该状态(读取)的所有可组合项的最低共同父项
  2. 状态应至少提升到它可以发生变化(写入)的最高级别
  3. 如果两种状态发生变化以响应相同的事件 ,它们应一起提升

LazyListState

官方文档解释: A state object that can be hoisted to control and observe scrolling.

文章参考:Compose 中的状态

相关推荐
糖墨夕1 分钟前
Trae还能将Figma 设计稿转化为前端代码
前端·trae
程序猿小D2 分钟前
第26节 Node.js 事件
服务器·前端·javascript·node.js·编辑器·ecmascript·vim
天天打码3 分钟前
Bootstrap Table开源的企业级数据表格集成
前端·开源·bootstrap
Allen Bright5 分钟前
【CSS-8】深入理解CSS选择器权重:掌握样式优先级的关键
前端·css
hnlucky7 分钟前
安装vue的教程——Windows Node.js Vue项目搭建
前端·javascript·vue.js·windows·node.js
余道各努力,千里自同风20 分钟前
CSS“多列布局”
前端·css·html
Keya26 分钟前
使用 tinypng 脚本打包为exe 进行压缩图片
前端·python·程序员
wordbaby32 分钟前
React Router 的 handle 和 useMatches 的作用、场景和联系
前端·react.js
我的div丢了肿么办32 分钟前
ResizeObserver和IntersectionObserver的详细讲解
前端·javascript·vue.js
凌览33 分钟前
斩获 7k Star,这个桌宠项目火了🔥
前端·javascript·后端