当前位置: 首页 > news >正文

CompositionLocal 用法

从前面的章节中我们已经了解到,在 Compose 中构建用户界面时,需要创建可组合函数的层级结构。

Compose 是状态驱动的,并且状态通常应在可组合层级的 “尽可能高的层级” 中声明(这一概念被称为 “状态提升”),再通过层级结构传递给需要该状态的子可组合项。这种方式在大多数场景下都能很好地工作,但如果状态需要通过层级结构中的 “多个层级” 向下传递,操作就会变得繁琐。而 Composition Local 正是解决这一问题的方案,本章将围绕它展开讲解。

理解 CompositionLocal

CompositionLocal 提供了一种方式:让在可组合项层级树中 “高层级” 声明的状态,能被树中 “低层级” 的函数使用,而无需在 “状态声明处” 与 “状态使用处” 之间的每一个可组合项中都传递该状态。

CompositionLocal

在这个层级中,一个名为 colorState 的状态在 Composable1 中声明,但仅在 Composable8 中使用。尽管 Composable3 和 Composable5 都不需要这个状态,colorState 仍需通过这两个函数传递,才能到达 Composable8。可组合项树的层级越深,状态传递经过的层级就越多。

解决这个问题就是使用 CompositionLocal。CompositionLocal 允许我们在树中 “必要的最高层级节点” 声明数据,之后在更深层次的可组合项中直接访问该数据,无需通过中间的子可组合项传递。

CompositionLocal

CompositionLocal 另一优势:它只会将数据提供给‌被赋值节点以下的子树分支‌。换句话说,若在调用 Composable3 时为该状态赋值,那么只有 Composable3、Composable5、Composable7 和 Composable8 能访问到该状态,而 Composable1、Composable2、Composable4 或 Composable6 无法访问。

这一特性使得状态可以 “局限在可组合项树的特定分支中”,且不同子分支可给同一个 CompositionLocal 状态分配不同的值。例如,Composable5 中为 colorState 分配的颜色,可与调用 Composable7 时设置的颜色不同。

使用 CompositionLocal

使用 CompositionLocal 声明状态,首先要创建一个 ProvidableCompositionLocal 实例,可通过调用 compositionLocalOf() 或 staticCompositionLocalOf() 函数获取该实例。

这两个函数都需要传入一个 lambda 表达式,用于定义在未指定具体值时为状态分配的默认值,例如:

val LocalColor = compositionLocalOf { Color.Red }
val LocalColor = staticCompositionLocalOf { Color.Red }

‌函数选择建议:‌

  • staticCompositionLocalOf():适用于‌不常变化‌的状态。因为状态值变更会导致赋值点以下整个组件树进行重组。
  • compositionLocalOf():适用于‌频繁变化‌的状态。它仅重组访问了当前状态的组件,性能更优。

接下来,需要为 ProvidableCompositionLocal 实例赋值,并在 CompositionLocalProvider 的调用中包裹对直接子可组合项的调用:

val color = Color.BlueCompositionLocalProvider(LocalColor provides color) {Composable5()
}

此时,Composable5 的所有后代组件都能通过 ProvidableCompositionLocal 实例的 current 属性访问该 CompositionLocal 状态,例如:

val background = LocalColor.current

创建 CompLocalDemo 项目

启动 Android Studio,创建 CompLocalDemo 的 “Empty Activity”项目。指定包名为 com.example.complocaldemo,选择最低 API 级别为 API 26(Android 8.0,Oreo)。

步骤 1:修改 MainActivity.kt 文件,删除并新增可组合函数。在 MainActivity.kt 文件中,删除默认的 Greeting 函数,然后添加 Composable1 的空可组合函数:

@Composable
fun Composable1(modifier: Modifier = Modifier) {}

步骤 2:编辑 onCreate() 方法,将原本调用 Greeting 的代码替换为调用 Composable1:

override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {CompLocalDemoTheme {Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->// 替换为调用 Composable1,并传入内边距参数Composable1(Modifier.padding(innerPadding))}}}
}

步骤 3:编辑 GreetingPreview 预览函数,将原本调用 Greeting 的代码替换为调用 Composable1:

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {CompLocalDemoTheme {// 替换为调用 Composable1Composable1()}
}

布局设计

在 MainActivity.kt 文件中,按如下方式实现可组合项层级结构:

// 导入所需依赖
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color// ...(其他已有代码)@Composable
fun Composable1(modifier: Modifier = Modifier) {Column {Composable2()Composable3()}
}@Composable
fun Composable2(modifier: Modifier = Modifier) {Composable4()
}@Composable
fun Composable3(modifier: Modifier = Modifier) {Composable5()
}@Composable
fun Composable4(modifier: Modifier = Modifier) {Composable6()
}@Composable
fun Composable5(modifier: Modifier = Modifier) {Composable7()Composable8()
}@Composable
fun Composable6(modifier: Modifier = Modifier) {Text("Composable 6")
}@Composable
fun Composable7(modifier: Modifier = Modifier) {// 空实现
}@Composable
fun Composable8(modifier: Modifier = Modifier) {Text("Composable 8")
}

层级结构如下所示

Composable1
├─ Composable2 → Composable4 → Composable6
└─ Composable3 → Composable5├─ Composable7└─ Composable8

添加 CompositionLocal 状态

本项目的使用一个 “colorState”:该状态可根据设备处于浅色模式还是深色模式自动切换,并用于控制 Composable8 中文本组件的背景色。由于该状态值不会频繁变化,因此我们可以使用 staticCompositionLocalOf() 函数。

在 MainActivity.kt 文件中,在 Composable1 声明上方添加以下代码:

// 定义 CompositionLocal 状态,默认颜色为 #ffdbcf(浅肤色)
val LocalColor = staticCompositionLocalOf { Color(0xFFffdbcf) }@Composable
fun Composable1(modifier: Modifier = Modifier) {Column {// ...(原有代码)}
}

接下来,需要添加 isSystemInDarkTheme() 函数的调用,根据其返回结果为 LocalColor 状态分配不同颜色;同时,需在 CompositionLocal 提供者的作用域内调用 Composable3。修改后的 Composable1 代码如下:

@Composable
fun Composable1(modifier: Modifier = Modifier) {// 根据系统主题模式分配颜色:深色模式用 #a08d87(深灰色),浅色模式用 #ffdbcf(浅肤色)val color = if (isSystemInDarkTheme()) {Color(0xFFa08d87)} else {Color(0xFFffdbcf)}Column {Composable2()// 在 CompositionLocalProvider 中提供 LocalColor 的值,作用域包含 Composable3 及其后代CompositionLocalProvider(LocalColor provides color) {Composable3()}}
}

访问 CompositionLocal 状态

在测试代码前,最后一项任务是将颜色状态赋值给 Composable8 中的 Text 组件,具体代码如下:

@Composable
fun Composable8(modifier: Modifier = Modifier) {// 通过 LocalColor.current 访问 CompositionLocal 状态,设置文本背景色Text("Composable 8", modifier.background(LocalColor.current))
}

测试

要在浅色模式和深色模式下测试代码,需在 MainActivity.kt 中新增一个预览可组合项,并将 uiMode 设置为 UI_NIGHT_MODE_YES(深色模式),代码如下:

@Preview(showBackground = true,uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES
)
@Composable
fun DarkPreview() {CompLocalDemoTheme {Composable1()}
}

刷新预览面板后,默认预览(浅色模式)和深色模式预览都会显示。两者中 Composable8 文本组件的背景色会不同,分别对应两种模式下的颜色设置。

CompositionLocal 案例

为不同可组合项设置不同颜色,修改代码,让 Composable3、Composable5、Composable7 和 Composable8 拥有不同的颜色设置。只需在调用每个可组合项时,用 CompositionLocalProvider 包裹,并为其分配不同颜色即可,具体代码如下:

  1. 修改 Composable3
@Composable
fun Composable3(modifier: Modifier = Modifier) {// 使用当前 LocalColor 颜色(从 Composable1 传递而来)Text("Composable 3", modifier.background(LocalColor.current))// 为 Composable5 分配红色CompositionLocalProvider(LocalColor provides Color.Red) {Composable5()}
}
  1. 修改 Composable5
@Composable
fun Composable5(modifier: Modifier = Modifier) {// 使用从 Composable3 传递的红色Text("Composable 5", modifier.background(LocalColor.current))// 为 Composable7 分配绿色CompositionLocalProvider(LocalColor provides Color.Green) {Composable7()}// 为 Composable8 分配黄色CompositionLocalProvider(LocalColor provides Color.Yellow) {Composable8()}
}
  1. 修改 Composable7
@Composable
fun Composable7(modifier: Modifier = Modifier) {// 使用从 Composable5 传递的绿色Text("Composable 7", modifier.background(LocalColor.current))
}

刷新预览面板后,这四个可组合项会呈现不同的颜色 —— 且它们都基于同一个 LocalColor 状态。

CompositionLocal 案例

测试 Composable6 对状态的访问权限,尝试从 Composable6 中访问 LocalColor 状态,修改代码如下:

@Composable
fun Composable6(modifier: Modifier = Modifier) {Text("Composable 6", modifier.background(LocalColor.current))
}

刷新预览后会发现,Composable6 的文本组件会使用 LocalColor 的默认颜色(而非 Composable1 中设置的模式颜色)。原因是:Composable6 位于组件树的另一个分支(Composable1→Composable2→Composable4→Composable6),无法访问到 Composable1 中为 LocalColor 设置的当前值。

小结

本章介绍了 CompositionLocal,并演示了如何通过它声明状态 —— 让布局层级中较低层级的可组合项能够访问该状态,而无需在子可组合项之间逐层传递。以这种方式声明的状态,其作用范围仅限于 “为其赋值的层级树分支”。

http://www.dtcms.com/a/525856.html

相关文章:

  • 怎样设计一个网站平台免费seo课程
  • EFM8开发系列
  • 哈尔滨网站优化咨询wordpress哪个模版好用
  • 网站策划ppt自己申请网站空间
  • 阿里云国际站GPU:阿里云GPU怎么释放实例?
  • Linux网络UDP(10)
  • 网站培训制度wap网站开发流程
  • 稳定网站服务器租用厦门网站建设公司
  • Linux实现每3天23点定时重启服务器
  • wordpress公司网站郑州网站seo服务
  • 【数据合成】Socratic-Zero 自动合成数据 指导课程学习
  • 2024包河初中组
  • “我店 + 微团“ 如何做到 “高频带低频“?拆解用户终身价值挖掘路径
  • 企业网站内容模块站酷官网入口
  • 沈阳做一个网站需要多少钱做c语言题目的网站
  • 涪城移动网站建设分销平台搭建
  • 想做个网站 怎么做建设企业网站电话
  • 网站优化推广公司织梦电影网站源码
  • 企业签合同,已进入“快签时代”
  • 【小白笔记】两数之和
  • 个人域名网站可以做企业站吗无广告自助建站
  • 网站下载的wordpress模板如何添加05网英语书
  • 从零使用vue脚手架开发一个简易的计算器
  • 兰州做网站价格网站开发成本计算
  • 1024水个贴
  • 怎么将自己做的网站放到网上seo外链推广平台
  • 产品策划书模板南昌seo排名
  • 韩国做美食的视频网站购物网站首页界面设计
  • 做海报图片的网站丽江网站开发
  • 深圳建设网站联系电话手机商城积分兑换