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 中的状态

相关推荐
zhengfei611几秒前
面向攻击性安全专业人员的一体化浏览器扩展程序[特殊字符]
前端·chrome·safari
码丁_11731 分钟前
为什么前端需要做优化?
前端
Mr Xu_43 分钟前
告别硬编码:前端项目中配置驱动的实战优化指南
前端·javascript·数据结构
Byron07071 小时前
从 0 到 1 搭建 Vue 前端工程化体系:提效、提质、降本实战落地
前端·javascript·vue.js
哆啦code梦1 小时前
前端存储三剑客:localStorage、sessionStorage与Cookie解析
前端·前端存储
徐小夕@趣谈前端2 小时前
Web文档的“Office时刻“:jitword共建版2.0发布!让浏览器变成本地生产力
前端·数据结构·vue.js·算法·开源·编辑器·es6
Data_Journal2 小时前
如何使用 Python 解析 JSON 数据
大数据·开发语言·前端·数据库·人工智能·php
德育处主任Pro2 小时前
纯前端网格路径规划:PathFinding.js的使用方法
开发语言·前端·javascript
墨笔.丹青2 小时前
基于QtQuick开发界面设计出简易的HarmonyUI界面----下
开发语言·前端·javascript
董世昌412 小时前
深度解析浅拷贝与深拷贝:底层逻辑、实现方式及实战避坑
前端·javascript·vue.js