
Embedded games in mobile apps: Make your app more attractive

11. Jan 2022
AndroidIn today's episode of the Jetpack Compose basics series, I'll show you how to use CompositionLocal to implicitly pass data via composition, which will make function parameters clearer.
How can you pass data down through composition? One way is to send them as function parameters to each composable explicitly, but in case of let's say colors or typography things can get pretty messy because you need them in almost every composable.
Your second option is to use CompositionLocal. It's tool for passing data through composition implicitly. E.g. MaterialTheme uses CompositionLocal under the hood to provide colors, shapes and typography anywhere.
Take a look at example code below. Color of texts is not changed directly in Text composable but LocalContentColor provider is used. This technique is widely used in Jetpack Compose framework and can be useful when you need to change attribute of all composables in scope. Current value of CompositionLocal corresponds to the closest value provided by ancestor in specified part of composition.
CompositionLocalProvider(LocalContentColor provides Color.Blue) {
// content color for all components in this scope is blue
Text(text = "Lorem")
CompositionLocalProvider(LocalContentColor provides Color.Red) {
// content color for all components in this scope is blue
Text(text = "ipsum")
Text(text = "dolor")
CompositionLocalProvider(LocalContentAlpha provides 0.2f) {
// alpha of all components in this scope is 0.2f
Text(text = "sit...")
}
}
}
If your question is - How can Text composable know which color or alpha to use? - answer is in implementation of Text composable. Color of Text composable is resolved by LocalContentColor.current call unless caller doesn't specify the color attribute.
val textColor = color.takeOrElse
style.color.takeOrElse {
LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
}
}
Firstly, CompositionLocal really makes sense especially when it can be potentially used by any descendant not by few of them. You should better think twice about whether you really want to create it or just use exmplicit parameters. It is not always the best solution and is not recommended to overuse it. Downside is that it's harder to make sure a value for every CompositionLocal is satisfied when dependencies are implicit.
Secondly, there should always be some value in CompositionLocal, while creation you default value should be provided.
There are 2 option to create Composition Local
// Definition with default value
val LocalPaddings = compositionLocalOf { PaddingValues(0.dp) }
.
.
.
// Using CompositionLocal App-wide
CompositionLocalProvider(LocalPaddings provides PaddingValues(24.dp)) {
/*
your app composables...
*/
}
Reading from created LocalPaddings can look like this. Box in example below now have app wide paddings - PaddingValues(24.dp).
Box(
modifier = Modifier.padding(LocalPaddings.current)
){
// some composable padded by 24.dp
}