我试图理解CompositionLocal实际上是如何隐含地设置值的,以及需要满足哪些要求才能使其发挥作用,但Android关于Locally scoped data with CompositionLocal的文档无济于事.

有一个示例,通过为color参数指定新值来更改Text的 colored颜色 .

// Some composable deep in the hierarchy of MaterialTheme
@Composable
fun SomeTextLabel(labelText: String) {
    Text(
        text = labelText,
        // `primary` is obtained from MaterialTheme's
        // LocalColors CompositionLocal
        color = MaterialTheme.colors.primary
    )
}

但如果您需要这样设置,这并不是隐含的!

然后他们展示了另一个例子,他们通过CompositionLocalProvider改变了ContentAlpha,这里Text suddenly可以隐式地使用新值,即使他们写的是CompositionLocal is what the Material theme uses under the hood.,那么为什么第一个例子不行呢?

@Composable
fun CompositionLocalExample() {
    MaterialTheme { // MaterialTheme sets ContentAlpha.high as default
        Column {
            Text("Uses MaterialTheme's provided alpha")
            CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
                Text("Medium value provided for LocalContentAlpha")
                Text("This Text also uses the medium value")
                CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
                    DescendantExample()
                }
            }
        }
    }
}

@Composable
fun DescendantExample() {
    // CompositionLocalProviders also work across composable functions
    Text("This Text uses the disabled alpha now")
}

还有第三个例子,他们展示了如何create your own CompositionLocal,但在这里,他们explicitly设置了Card‘S elevation参数!

@Composable
fun SomeComposable() {
    // Access the globally defined LocalElevations variable to get the
    // current Elevations in this part of the Composition
    Card(elevation = LocalElevations.current.card) {
        // Content
    }
}

他们创造CompositionLocalProvider难道不是为了避免这样做吗?

            // Bind elevation as the value for LocalElevations
            CompositionLocalProvider(LocalElevations provides elevations) {
                // ... Content goes here ...
                // This part of Composition will see the `elevations` instance
                // when accessing LocalElevations.current
            }

推荐答案

@Composable
fun CompositionLocalExample() {
    MaterialTheme { // MaterialTheme sets ContentAlpha.high as default
        Column {
            Text("Uses MaterialTheme's provided alpha")
            CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
                Text("Medium value provided for LocalContentAlpha")
                Text("This Text also uses the medium value")
                CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
                    DescendantExample()
                }
            }
        }
    }
}

在此示例中,Text使用LocalContentAlpha.current值将Alpha设置为source code

val localContentColor = LocalContentColor.current
val localContentAlpha = LocalContentAlpha.current
val overrideColorOrUnspecified: Color = if (color.isSpecified) {
    color
} else if (style.color.isSpecified) {
    style.color
} else {
    localContentColor.copy(localContentAlpha)
}

由于该变化的值LocalContentAlpha提供了Alpha Text所获得的变化.

与第三个示例中一样,其中高程设置为

使用CompostionLocal CompostionLocal.Current将返回 由最近的CompostionLocalProvider提供的 该CompostionLocal的值:

@Composable
fun SomeComposable() {
    // Access the globally defined LocalElevations variable to get the
    // current Elevations in this part of the Composition
    Card(elevation = LocalElevations.current.card) {
        // Content
    }
}

还有,例如,使用具有默认色调的图标

tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)

您可以应用LocalContent Alpha或LocalContent Color来更改默认的色调值或显式更改参数本身.

@Preview
@Composable
private fun Test() {

    Column(
        Modifier
            .fillMaxSize()
            .padding(10.dp)
    ) {

        // Default icon
        Icon(
            imageVector = Icons.Default.Favorite,
            contentDescription = null
        )
        Spacer(modifier = Modifier.height(10.dp))

        Icon(
            imageVector = Icons.Default.Favorite,
            contentDescription = null,
            tint = Color.Green
        )
        Spacer(modifier = Modifier.height(10.dp))

        Icon(
            modifier = Modifier.alpha(.3f),
            imageVector = Icons.Default.Favorite,
            tint = Color.Green,
            contentDescription = null
        )
        Spacer(modifier = Modifier.height(10.dp))

        // Icon uses tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
        // changing it also changes default tint
        CompositionLocalProvider(LocalContentColor provides Color.Green) {
            Icon(
                imageVector = Icons.Default.Favorite,
                contentDescription = null
            )
        }
        Spacer(modifier = Modifier.height(10.dp))

        CompositionLocalProvider(LocalContentAlpha provides .3f) {
            CompositionLocalProvider(LocalContentColor provides Color.Green) {
                Icon(
                    imageVector = Icons.Default.Favorite,
                    contentDescription = null
                )
            }
        }
    }
}

Kotlin相关问答推荐

Spring Boot Bean验证器未触发

如何使用multiset与JOOQ获取关联的记录列表?

Kotlin supervisorScope 即使包裹在 try catch 中也会失败

如何在 Kotlin 中不受约束?

从 HashMap 检索时的 NPE,即使 containsKey() 在多线程环境中返回 true

匹配在单词边界上包含特殊字符的变量字符串的正则表达式

具有多个不同类型来源的 LiveData

未为任务启用 Gradle 构建缓存

SpringBoot 2.5.0 对于 Jackson Kotlin 类的支持,请在类路径中添加com.fasterxml.jackson.module: jackson-module-kotlin

Kotlin - 覆盖方法中的 IllegalArgumentException

使用 Paging 3 时保存并保留 LazyColumn 滚动位置

如何将命令行参数传递给Gradle Kotlin DSL

Kotlin 扩展函数 - 覆盖现有方法

Kotlin通过映射委托属性,如果映射中不存在,则抛出NoTouchElementException

使用 Kotlin 创建自定义 Dagger 2 范围

项目未与 Gradle 链接

Android Jetpack导航,另一个主机片段中的主机片段

内联 onFocusChange kotlin

如何在Kotlin中使用Handler和handleMessage?

将协程更新到 1.2.0 后构建失败:META-INF/atomicfu.kotlin_module