
Náš Android tech stack pro vývoj mobilních aplikací

28. Feb 2023
AndroidV dnešnej epizóde série Jetpack Compose Basics vám ukážem, ako použiť CompositionLocal na implicitné odovzdávanie údajov cez kompozíciu, vďaka čomu bude zoznam parametrov funkcie prehľadnejší.
Jak můžete předat data prostřednictvím kompozice? Jednou z cest je poslat je, jako parametry do každého composable, ale v případě barev nebo typografie může být situace dost chaotická, protože je potřebujete téměř v každém composable.
Druhou možností je použít CompositionLocal. Je to nástroj pro implicitní odevzdávání údajů s kompozicí, např. MaterialTheme využívá CompositionLocal k poskytování barev, tvarů a typografie kdekoli.
Podívejte se na příklad kódu níže. Barva textů se v Text composable nemění přímo, ale používá se provider LocalContentColor. Tato technika se v rámci Jetpack Compose používá velmi hojně a může být užitečná, pokud potřebujete změnit atribut všech položek composables ve scope. Aktuální hodnota CompositionLocal odpovídá nejbližší hodnotě poskytnuté předkem ve specifikované části kompozice.
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...")
}
}
}
Pokud vaše otázka zní: Jak může Text composable vědět, jakou barvu nebo alfu použít? – odpověď je v implementaci Text composable. Barva textu se určí pomocí LocalContentColor.current, pokud caller nespecifikuje atribut color.
val textColor = color.takeOrElse {
style.color.takeOrElse {
LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
}
}
Zaprvé, CompositionLocal skutečně dává smysl, zejména pokud ho může potenciálně použít jakýkoli potomek, nejen několik z nich. Raději si dvakrát rozmyslete, zda ho chcete opravdu vytvořit, nebo zda chcete použít explicitní parametry. Ne vždy je to nejlepší řešení a nedoporučuje se to přehánět. Nevýhodou je, že je těžší zajistit, aby byla hodnota každého CompositionLocal splněna, pokud vznikají implicitní závislosti.
Za druhé, v CompositionLocal by měla být vždy nějaká hodnota, přičemž při vytváření by měla být poskytnuta vaše předvolená hodnota.
Existují 2 možnosti vytvoření CompositionLocal
// Definition with default value
val LocalPaddings = compositionLocalOf { PaddingValues(0.dp) }
.
.
.
// Using CompositionLocal App-wide
CompositionLocalProvider(LocalPaddings provides PaddingValues(24.dp)) {
/*
your app composables...
*/
}
Čtení z vytvořených LocalPaddings může vypadat takto. Box v níže uvedeném příkladu má teď paddings pro celou aplikaci – PaddingValues (24 dp).
Box(
modifier = Modifier.padding(LocalPaddings.current)
){
// some composable padded by 24.dp
}