28. Feb 2023Android

Jetpack Compose Basics – Jak používat a vytvořit vlastní CompositionLocal

V 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ší.

Peter ŠulyAndroid developer

Co je CompositionLocal v Jetpack Compose?

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.

Jak používat CompositionLocal v Jetpack Compose?

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...")
        }
    }
}
Příklad použití LocalContentColor
Příklad použití LocalContentColor

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)
    }
}

Jak vytvořit vlastní CompositionLocal?

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

  • compositionLocalOf – změna hodnoty znehodnotí pouze obsah, který čte jeho aktuální hodnotu
  • staticCompositionLocalOf – čtení nesleduje Compose. Změna hodnoty způsobí, že se překomponuje celý obsah lambda, nejen místa, kde se načítá aktuální hodnota.
// 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
}

Další články ze série Jetpack Compose Basics:

Peter ŠulyAndroid developer