Skip to content

参考资料:https://developer.android.google.cn/jetpack/compose/compositionlocal?hl=zh-cn

什么是CompositionLocal

函数调用的参数传递方式: 显示传参需要层层传递。 隐式传参,定义全局变量。 image.png

显示传参

参数需要层层床底比较繁琐

kotlin
/**
 * 显式传参
 */
class ExplicitText {
    fun Layout() {
        var color: String = "black"
        //参数需要层层床底比较繁琐
        Text(color)
        Grid(color)
    }


    private fun Grid(color: String) {
        println("other components in Grid")
        Text(color)
    }

    private fun Text(color: String) {
        println(color)
    }

}

fun main() {
    val ep = ExplicitText()
    ep.Layout()
}

隐式传参

隐式传参就是通过定义一个全局变量的方式,在同一作用域下的所有方法都能访问到它,参数直接传递。 但是全局变量带来的问题,一经修改,影响之后被调用的所有参数 如下我们指向改变传给Grid函数的参数的值为“红色”,而不影响之后第二次调用的Text函数。如果使用如下的方式,必然会影响之后被调用的所有参数

kotlin
class ImplicitTest {
    var color: String = "黑色"

    fun Layout() {
        Text()
        color="红色"
        //全局变量带来的问题,一经修改,影响之后被调用的所有参数
        Grid()
        Text()
    }


    private fun Grid() {
        println("other components in Grid")
        Text()
    }

    private fun Text() {
        println(color)
    }
}

fun main() {
    val ip = ImplicitTest()
    ip.Layout()
}
//输出
黑色
other components in Grid
红色
红色

要解决这个问题,只需要在调用Grid之前修改color的值,在调用完成后再修改回来即可。

kotlin
class ImplicitTest {
    var color: String = "黑色"

    fun Layout() {
        Text()
        provider("红色",color){
            Grid()
        }
        Text()
    }


    fun provider(value:String,perValue: String,content:(()->Unit)){
        color=value
        content()
        color=perValue
    }

    private fun Grid() {
        println("other components in Grid")
        Text()
    }

    private fun Text() {
        println(color)
    }
}

fun main() {
    val ip = ImplicitTest()
    ip.Layout()
}
//输出
黑色
other components in Grid
红色
黑色

image.png

在Compose中什么情况下会运用到隐式传参呢? image.png 通常情况下,在compose中,数据以参数形式向下流经整个界面树传递给每个可组合函数。但是,对于广泛使用的常用数据(如颜色或类型样式),这可能会很麻烦。 为了支持无需将颜色作为显式参数依赖项传递给大多数可组合项,compose提供了CompositionLocal,可以创建以界面树为作用域的具名对象,这可以用作让数据流经界面树的一种隐式方式。 image.png

在主题中的使用

主题就是全局对象,里面的属性,可以被主题对象包裹的所有组件访问和引用,如果要修改某一个组件子树的主题或者属性,就可以使用上面例子中的方法。 而Compose中通过CompositionLocalProvider来为组件属性提供新值 image.png

kotlin
@Composable
fun Sample() {
    MaterialTheme {
        Column {
            Text(text = "hello world hello world hello world ")
            CompositionLocalProvider(LocalContentColor provides LocalContentColor.current.copy(alpha = 0.73f)) {
                Text(text = "hello world hello world hello world ")
                Text(text = "hello world hello world hello world ")
                CompositionLocalProvider(
                    LocalContentColor provides LocalContentColor.current.copy(
                        alpha = 0.37f
                    )
                ) {
                    Text(text = "hello world hello world hello world ")
                    Text(text = "hello world hello world hello world ")
                }
            }
        }
    }
}

image.png

上下文Context

组件中的Context也是一个全局变量,不会在组件树中层层传递

kotlin
/**
 * Provides a [Context] that can be used by Android applications.
 */
val LocalContext = staticCompositionLocalOf<Context> {
    noLocalProvidedFor("LocalContext")
}

例如在任何位置,我们可以获取到上下文,并通过它来获取资源文件。

kotlin
@Composable
fun FruitText(size: Int) {
    val resources = LocalContext.current.resources
    val text = resources.getString(R.string.app_name)
    Text(text = "$size  $text")
}

自定义CompositionLocal

实现一个不同卡片海拔高度的卡片层叠布局 首先创建一个卡片的组件 略