设计师网站兼职,免费开源网站系统,淄博网站建设yx718,网页制作工具有什么Compose 官方说明一直很简洁#xff1a;CompositionLocal 是通过组合隐式向下传递数据的工具。 两个核心#xff1a;隐式、向下传递#xff0c;咋一看很懵#xff0c;先不着急去理解#xff0c;我们先看一段非常简单的代码#xff1a;
class MainActivity : ComponentAc…Compose 官方说明一直很简洁CompositionLocal 是通过组合隐式向下传递数据的工具。 两个核心隐式、向下传递咋一看很懵先不着急去理解我们先看一段非常简单的代码
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposeBlogTheme {val name Hi, Compose! // name 是局部变量ShowMessage(name)}}}
}Composable
fun ShowMessage(message: String) {Text(message)
}这段代码中局部变量 name 以参数的方式被暴露出来了在 Compose 中这叫做 State Hoisting状态提升。
现在思考两个问题
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposeBlogTheme {val name Hi, Compose!ShowMessage(name)} name // 思考 1: 这边能不能获取到 name}}
}Composable
fun ShowMessage(message: String) { name // 思考 2: 这边能不能获取到 nameText(message)
}很明显都是不行的因为 name 这个局部变量的 作用域 是限定在 ComposeBlogTheme {} 范围内的。
现在我们再来改下代码
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposeBlogTheme {val name Hi, Compose!// ShowMessage(name) // 这段代码我不要了}}}
}Composable
fun ShowMessage() { // 参数我也去掉不需要外面传参进来Text(name) // 我就直接把外面的 name 写到这里直接用
}这样写行吗肯定是不行的但我就想这么写并且希望它可以运行那么这种行为就意味着 name 这个局部变量要拥有可以穿出它的 作用域并且穿透进 showMessage 函数的能力
好消息这种牛逼的行为就可以通过我们的主角CompositionLocal 实现它提供了这种 「穿透能力」。
再来看两张图你就更加明白 CompositionLocal 的神奇之处了。 我来解释一下这张图绿色可组合项有个 stateData 参数这个参数又跟顶层的可组合项有联系正常代码中对于这种关联我们一般就是要不停的传参很明显图中蓝色的可组合项就做了这些事但这样你会发现层积越多参数可能就越多因为别的可组合项也可能有自己的参数这样代码的阅读和理解会特别费劲。
那如果用 CompositionLocal 呢 现在整个树中不再需要蓝色的可组合项传递参数哪里需要用 stateData直接用就是了因为顶层可组合项中通过 CompositonLocal 赋予了状态数据可以穿透的能力
到这里你应该对 CompositionLocal 已经有了一个比较透测的理解了接下来我们看看如何使用。 CompositionLocal 现在我们就来实现一个 CompostionLocal 功能让上面的代码生效总共需要经历三步
1. 创建 CompositionLocal 实例
首先创建一个具有 「穿透能力」 的变量
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposeBlogTheme {val name Hi, Compose!}}}
}Composable
fun ShowMessage() {Text(name)
}// 1. 通过 compostionLocalOf 创建 CompositionLocal
val LocalName compositionLocalOfString { Compose }注意在 Compose 中一般定义这种具有「穿透能力」的 CompostionLocal它的名称有个约定俗成的写法LocalXXX。 2. 为 CompositionLocal 提供值
CompostionLocal 实例定义好了我们要通过 provides 给它绑定一个值。
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposeBlogTheme {val name Hi, Compose!// 2. CompositionLocalProvider 可组合项可将值绑定到给定层次结构的 CompositionLocal 实例CompositionLocalProvider(LocalName provides name) {ShowMessage()}}}}
}Composable
fun ShowMessage() {Text(name)
}// 1. 通过 compostionLocalOf 创建 CompositionLocal
val LocalName compositionLocalOfString { Compose }3. 获取 CompositionLocal 数据
前面两步其实就已经创建好了一个包含 数据 可穿透 的 CompositionLocal 了最后一步就是获取到其中的数据。
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposeBlogTheme {val name Hi, Compose!// 2. CompositionLocalProvider 可组合项可将值绑定到给定层次结构的 CompositionLocal 实例CompositionLocalProvider(LocalName provides name) {ShowMessage()}}}}
}Composable
fun ShowMessage() {// 3. 获取 nameText(LocalName.current)
}// 1. 通过 compostionLocalOf 创建 CompositionLocal
val LocalName compositionLocalOfString { Compose }现在运行程序试试 两种创建方式 前面的例子我们使用 compositionLocalOf 创建 CompositionLocal另外官方还提供了 staticCompositionLocalOf。
compositionLocalOf在重组期间更改提供的值只会使读取其 current 值的内容无效。staticCompositionLocalOf与 compositionLocalOf 不同Compose 不会跟踪 staticCompositionLocalOf 的读取。更改该值会导致提供 CompositionLocal 的整个 content lambda 被重组而不仅仅是在组合中读取 current 值的位置。
没看懂我们来看下面的代码
1. compositionLocalOf
class MainActivity : ComponentActivity() {private val themeBackground by mutableStateOf(Color.Blue)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposeBlogTheme {CompositionLocalProvider(LocalBackground provides Color.Red) {TextBackground()CompositionLocalProvider(LocalBackground provides themeBackground) {/*** 2. themeBackground 变化后仅此范围重组* TextBackground()*/CompositionLocalProvider(LocalBackground provides Color.Red) {TextBackground()}}TextBackground()}}}}
}Composable
fun TextBackground() {Surface(color LocalBackground.current) {Text(Hi, Compose)}
}// 1. Compose 会记录跟踪每一个调用 LocalBackground.current 的区域
val LocalBackground compositionLocalOf { Color.Blue }2. staticCompositionLocalOf
class MainActivity : ComponentActivity() {private val themeBackground by mutableStateOf(Color.Blue)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposeBlogTheme {CompositionLocalProvider(LocalBackground provides Color.Red) {TextBackground()CompositionLocalProvider(LocalBackground provides themeBackground) {/*** 2. themeBackground 变化后内部所有 content 全部重组* TextBackground()** CompositionLocalProvider(LocalBackground provides Color.Red) {* TextBackground()* }*/}TextBackground()}}}}
}Composable
fun TextBackground() {Surface(color LocalBackground.current) {Text(Hi, Compose)}
}// Compose 不会记录跟踪每一个调用 LocalBackground.current 的区域
val LocalBackground staticCompositionLocalOf { Color.Blue }那么随之而来一个疑问我们该用哪个创建 CompositionLocal
3. 官方建议
如果为 CompositionLocal 提供的值发生更改的可能性微乎其微或永远不会更改使用 staticCompositionLocalOf 可提高性能。
比如我们看两个系统里面定义好的 CompositionLocal
// 上下文固定不变用 staticCompositionLocalOf
val LocalContext staticCompositionLocalOfContext {noLocalProvidedFor(LocalContext)
}// 内部内容颜色常变用 compositionLocalOf
val LocalContentColor compositionLocalOf { Color.Black }CompositionLocal 应用场景 这里我们列举一些 CompositionLocal 的适用场景。
1. 提供上下文
LocalContext.current // 是不是很熟悉这其实就相当于 getContext()2. MaterialTheme
其实官方的 MaterialTheme 就用到了 CompositionLocal我们看源码
Composable
fun MaterialTheme(colors: Colors MaterialTheme.colors,typography: Typography MaterialTheme.typography,shapes: Shapes MaterialTheme.shapes,content: Composable () - Unit
) {val rememberedColors remember { colors.copy() }.apply { updateColorsFrom(colors) }val rippleIndication rememberRipple()val selectionColors rememberTextSelectionColors(rememberedColors)// 通过 providers 将 rememberedColors 提供给了 LocalColorsCompositionLocalProvider(LocalColors provides rememberedColors,LocalContentAlpha provides ContentAlpha.high,LocalIndication provides rippleIndication,LocalRippleTheme provides MaterialRippleTheme,LocalShapes provides shapes,LocalTextSelectionColors provides selectionColors,LocalTypography provides typography) {ProvideTextStyle(value typography.body1) {PlatformMaterialTheme(content)}}
}object MaterialTheme {val colors: ColorsComposableReadOnlyComposableget() LocalColors.currentval typography: TypographyComposableReadOnlyComposableget() LocalTypography.currentval shapes: ShapesComposableReadOnlyComposableget() LocalShapes.current
}