Compose基础知识--隐式向下传递数据的工具 ( CompositionLocal )

153 阅读2分钟

介绍与使用

介绍

CompositionLocal 是通过组合隐式向下传递数据的工具

通俗一点的讲法就是:在任意一个使用@Compose注解声明的函数, 都能访问到声明的CompositionLocal声明的变量。有点类似于静态变量,全局任何一个类,任何一个方法都能访问这个全局的静态变量。

使用示例

声明CompositionLocal类型的变量
// LocalElevations.kt file

data class Elevations(val card: Dp = 0.dp, val default: Dp = 0.dp)

// Define a CompositionLocal global object with a default
// This instance can be accessed by all composables in the app
val LocalElevations = compositionLocalOf { Elevations() }

上面声明了一个Elevation实体类,使用compositionLocalOf{} 包裹一下Elecations对象。这就完成了CompositionLocal的声明,是不是很简单。

使用上面声明的CompositionLocal变量

// MyActivity.kt file

class MyActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            // Calculate elevations based on the system theme
            val elevations = Elevations(card = 0.dp, default = 0.dp)

            // Bind elevation as the value for LocalElevations
            CompositionLocalProvider(LocalElevations provides elevations) {
                // ... Content goes here ...
                Text("Hello World!!")
            }
        }
    }
}

@Compose
fun Text(str: String) {
    // 通过LocalElevations.current可以获取到声明的变量值
    val alpha = LocalElevations.current.card
    Box {
        Text(
            text = str,
            modifier = Modifier.alpha(alpha)
        )
    }
}

通过CompositionLocalProvide方法,定义一个CompositionLocal类型变量。这个变量的作用域是UI树。UI树意思就是通过compose函数定义的UI组合构成了一颗完整的UI树。在这个UI树中的任意地方都可以访问到声明的LocalElevations, 比通过函数参数输入的方式,这种隐式输入的方式给开发者带来更高的开发效率

特性介绍

CompositiongLocal类型的变量除了能够在Compose的UI树中隐式注入快捷读取外,还能局部更改compositionLocal的值,并且只影响部分UI树的子节点读取该值。以外的UI树子节点读取值不受影响。

@Composable
fun CompositionLocalExample() {
    MaterialTheme { // MaterialTheme sets ContentAlpha.high as default
        Column {
            // 默认值为0
            
            //读取到的值为0
            Text("Uses MaterialTheme's provided alpha")
            // 更改值为1
            CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
                //读取值是1
                Text("Medium value provided for LocalContentAlpha")
                Text("This Text also uses the medium value")
                // 更改值为2
                CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
                    // 读取值为2
                    DescendantExample()
                }
            }
            // 读取到的值为0
            Text("Uses MaterialTheme's provided alpha")
        }
    }
}

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

CompositionLocalProvider 用于为一部分的组合提供不同的值,不影响全局数据

使用注意事项

CompositionLocal使得可组合项的行为更难推断

  1. 在创建隐式依赖项时,使用这些依赖项的可组合项的调用方需要确保为每个 CompositionLocal 提供一个值。
  2. 此外,该依赖项可能没有明确的可信来源,因为它可能会在组合中的任何部分发生改变。因此,在出现问题时调试应用可能更具有挑战性因为需要向上查看组合,了解提供 current 值的位置

CompositionLocal 应具有合适的默认值