CompositionLocal
ist ein Tool für
Daten implizit durch die Komposition weitergeleitet werden. Auf dieser Seite werden Sie
mehr über CompositionLocal
erfahren, wie Sie eigene erstellen
CompositionLocal
. Wenn CompositionLocal
eine gute Lösung ist,
Ihren Anwendungsfall.
Jetzt neu: CompositionLocal
Normalerweise fließen Daten beim Schreiben durch die UI-Baum als Parameter für jede zusammensetzbare Funktion Dadurch wird das explizit sind. Dies kann bei Daten, die sehr umfangreich sind, jedoch umständlich sein. häufig und weit verbreitet, wie Farben oder Schriftstile. Weitere Informationen: Beispiel:
@Composable fun MyApp() { // Theme information tends to be defined near the root of the application val colors = colors() } // Some composable deep in the hierarchy @Composable fun SomeTextLabel(labelText: String) { Text( text = labelText, color = colors.onPrimary // ← need to access colors here ) }
Um zu unterstützen, dass die Farben nicht als explizite Parameterabhängigkeit an
Mit der Option Compose AngeboteCompositionLocal
können Sie
zum Erstellen von benannten Objekten auf Baumebene,
die implizit verwendet werden können, um
Datenfluss durch den UI-Baum.
CompositionLocal
-Elemente werden normalerweise mit einem Wert in einem bestimmten Knoten bereitgestellt
des UI-Baums. Dieser Wert kann von seinen zusammensetzbaren Nachfolgerelementen verwendet werden, ohne
Sie legen CompositionLocal
als Parameter in der zusammensetzbaren Funktion fest.
Im Hintergrund wird CompositionLocal
verwendet.
MaterialTheme
ist
ein Objekt, das drei CompositionLocal
-Instanzen bereitstellt: colorScheme
,
typography
und shapes
, sodass Sie sie später in einem beliebigen
als Teil der Komposition.
Im Einzelnen sind dies die LocalColorScheme
, LocalShapes
und
LocalTypography
-Properties, auf die du über die MaterialTheme
zugreifen kannst
colorScheme
, shapes
und typography
.
@Composable fun MyApp() { // Provides a Theme whose values are propagated down its `content` MaterialTheme { // New values for colorScheme, typography, and shapes are available // in MaterialTheme's content lambda. // ... content here ... } } // Some composable deep in the hierarchy of MaterialTheme @Composable fun SomeTextLabel(labelText: String) { Text( text = labelText, // `primary` is obtained from MaterialTheme's // LocalColors CompositionLocal color = MaterialTheme.colorScheme.primary ) }
Eine CompositionLocal
-Instanz ist auf einen Teil der Komposition beschränkt, sodass Sie
können verschiedene Werte auf
verschiedenen Ebenen der Baumstruktur bereitgestellt werden. Der Wert current
einer CompositionLocal
entspricht dem nächstgelegenen Wert, der von einem
Ancestors in diesem Teil der Komposition.
Um einen neuen Wert für CompositionLocal
festzulegen, verwenden Sie die Methode
CompositionLocalProvider
und dessen provides
infix-Funktion, die einen CompositionLocal
-Schlüssel mit value
verknüpft. Die
content
Lambda von CompositionLocalProvider
wird bereitgestellt
-Wert beim Zugriff auf die current
-Eigenschaft von CompositionLocal
. Wenn ein
wird ein neuer Wert angegeben, setzt "Compose" Teile der Komposition neu zusammen,
CompositionLocal
.
Als Beispiel enthält die CompositionLocal
-Datei LocalContentColor
die bevorzugte Inhaltsfarbe für Text und
damit sie sich von der aktuellen Hintergrundfarbe abhebt. Im
Im folgenden Beispiel wird CompositionLocalProvider
verwendet,
für verschiedene Teile der Komposition.
@Composable fun CompositionLocalExample() { MaterialTheme { // Surface provides contentColorFor(MaterialTheme.colorScheme.surface) by default // This is to automatically make text and other content contrast to the background // correctly. Surface { Column { Text("Uses Surface's provided content color") CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.primary) { Text("Primary color provided by LocalContentColor") Text("This Text also uses primary as textColor") CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.error) { DescendantExample() } } } } } } @Composable fun DescendantExample() { // CompositionLocalProviders also work across composable functions Text("This Text uses the error color now") }
Abbildung 1: Vorschau der zusammensetzbaren Funktion CompositionLocalExample
.
Im letzten Beispiel wurden die CompositionLocal
-Instanzen intern verwendet
durch „Material Componables“. So greifen Sie auf den aktuellen Wert einer CompositionLocal
zu:
Verwenden Sie die current
Property. Im folgenden Beispiel wird der aktuelle Wert Context
von LocalContext
CompositionLocal
, das häufig in Android-Apps verwendet wird, dient der Formatierung
Text:
@Composable fun FruitText(fruitSize: Int) { // Get `resources` from the current value of LocalContext val resources = LocalContext.current.resources val fruitText = remember(resources, fruitSize) { resources.getQuantityString(R.plurals.fruit_title, fruitSize) } Text(text = fruitText) }
Eigenes CompositionLocal
erstellen
CompositionLocal
ist ein Tool zum Übergeben von Daten durch die Komposition
implizit.
Ein weiteres wichtiges Signal für die Verwendung von CompositionLocal
ist, dass der Parameter
übergreifende und Zwischenschichten der Implementierung nicht wissen,
vorhanden ist, da die Erkennung dieser Zwischenebenen den
der zusammensetzbaren Funktion. Die Abfrage von Android-Berechtigungen
was sich CompositionLocal
unter der Haube bietet. Eine zusammensetzbare Media-Auswahl
neue Funktionen für den Zugriff auf berechtigungsgeschützte Inhalte auf der
Gerät verwenden, ohne die API zu ändern und die Aufrufer der Media-Auswahl
berücksichtigen Sie diesen zusätzlichen Kontext,
der aus der Umgebung verwendet wird.
CompositionLocal
ist jedoch nicht immer die beste Lösung. Mi.
Vermeide eine zu häufige Verwendung von CompositionLocal
, da dies einige Nachteile hat:
Mit CompositionLocal
lässt sich das Verhalten einer zusammensetzbaren Funktion erschweren. Als
erstellen implizite Abhängigkeiten, die Aufrufer
von zusammensetzbaren Funktionen, die diese verwenden,
um sicherzustellen, dass ein Wert für jeden CompositionLocal
erfüllt ist.
Darüber hinaus gibt es möglicherweise keine eindeutige Datenquelle für diese Abhängigkeit, da sie
können an einem beliebigen
Teil der Komposition angepasst werden. Das Debugging der App
auftreten, kann schwieriger sein, da Sie die
Zusammensetzung, um zu sehen, wo der Wert current
angegeben wurde. Tools wie Suchen
Nutzungen in der IDE oder im Compose layout Inspector (Layout-Inspektor verfassen), um genügend Informationen
dieses Problem zu beheben.
Entscheiden, ob CompositionLocal
verwendet werden soll
CompositionLocal
kann eine gute Lösung sein, wenn bestimmte Bedingungen erfüllt sind.
für Ihren Anwendungsfall:
Ein CompositionLocal
sollte einen guten Standardwert haben. Wenn kein Standardwert vorhanden ist
müssen Sie garantieren, dass es für einen Entwickler außerordentlich schwierig ist,
für den Fall, dass für CompositionLocal
kein Wert angegeben ist.
Wenn Sie keinen Standardwert angeben, kann dies zu Problemen und Frust beim Erstellen
oder eine Vorschau einer zusammensetzbaren Funktion mit dieser CompositionLocal
-Funktion ausführen,
explizit angegeben werden.
Vermeiden Sie CompositionLocal
für Konzepte, die nicht als baumbezogen oder
auf Ebene der untergeordneten Hierarchie. Ein CompositionLocal
ist sinnvoll, wenn es
möglicherweise von allen Nachfolgern
verwendet werden, nicht von einigen wenigen.
Wenn Ihr Anwendungsfall diese Anforderungen nicht erfüllt, sehen Sie sich die
Abschnitt Alternativen, bevor Sie eine
CompositionLocal
Ein Beispiel für eine unzulässige Vorgehensweise ist das Erstellen einer CompositionLocal
, die den
ViewModel
eines bestimmten Bildschirms, sodass alle zusammensetzbaren Funktionen in diesem Bildschirm
einen Verweis auf das ViewModel
abzurufen, um eine Logik auszuführen. Das ist nicht empfehlenswert
da nicht alle zusammensetzbaren Funktionen unter einem bestimmten UI-Baum Informationen zum
ViewModel
Es hat sich bewährt, nur die Informationen
dass sie dem Muster folgen müssen, dass der Zustand nach unten und Ereignisse nach oben fließen. Mit diesem Ansatz werden Ihre zusammensetzbaren Funktionen
wiederverwendbar und leichter zu testen.
CompositionLocal
wird erstellt
Es gibt zwei APIs zum Erstellen einer CompositionLocal
:
compositionLocalOf
: Wenn der Wert während der Neuzusammensetzung geändert wird, werden nur ungültig. den Inhalt, der seinecurrent
Wert.staticCompositionLocalOf
: Im Gegensatz zucompositionLocalOf
sind Lesevorgänge einerstaticCompositionLocalOf
nicht von Compose verfolgt. Wenn Sie den Wert ändern, wird der Wert fürcontent
vollständig Lambda-Funktion, bei der dasCompositionLocal
zur Neuzusammensetzung bereitgestellt wird, nur die Stellen, an denen dercurrent
-Wert in der Zusammensetzung gelesen wird.
Es ist sehr unwahrscheinlich, dass sich der für CompositionLocal
angegebene Wert ändert oder
ändert sich nichts. Verwenden Sie staticCompositionLocalOf
, um die Leistung zu verbessern.
Beispielsweise kann das Designsystem einer App anders formuliert sein,
werden mit einem Schatten
für die UI-Komponente erhöht. Da die unterschiedlichen
Höhen für die Anwendung sollten im gesamten UI-Baum verteilt werden. Wir verwenden einen
CompositionLocal
Da der Wert CompositionLocal
bedingt abgeleitet wird
verwenden wir die compositionLocalOf
API:
// 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() }
Werte für CompositionLocal
angeben
Das CompositionLocalProvider
zusammensetzbare Funktion bindet Werte an CompositionLocal
-Instanzen für die
Hierarchie. Um einen neuen Wert für CompositionLocal
festzulegen, verwenden Sie die Methode
provides
infix-Funktion, die wie folgt einen CompositionLocal
-Schlüssel mit einem value
verknüpft:
// MyActivity.kt file class MyActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { // Calculate elevations based on the system theme val elevations = if (isSystemInDarkTheme()) { Elevations(card = 1.dp, default = 1.dp) } else { Elevations(card = 0.dp, default = 0.dp) } // Bind elevation as the value for LocalElevations CompositionLocalProvider(LocalElevations provides elevations) { // ... Content goes here ... // This part of Composition will see the `elevations` instance // when accessing LocalElevations.current } } } }
CompositionLocal
nutzen
CompositionLocal.current
gibt den Wert des nächstgelegenen CompositionLocalProvider
zurück, der einen Wert für CompositionLocal
bereitstellt:
@Composable fun SomeComposable() { // Access the globally defined LocalElevations variable to get the // current Elevations in this part of the Composition MyCard(elevation = LocalElevations.current.card) { // Content } }
Mögliche Alternativen
CompositionLocal
kann für manche Anwendungsfälle eine übermäßige Lösung sein. Wenn Ihr
Anwendungsfall nicht die Kriterien erfüllt, die unter Verwendung
CompositionLocal angezeigt wird, könnte eine andere Lösung wahrscheinlich besser sein
die für Ihren Anwendungsfall geeignet sind.
Explizite Parameter übergeben
Es ist eine gute Gewohnheit, die Abhängigkeiten der zusammensetzbaren Funktion explizit anzugeben. Wir empfehlen, Sie zusammensetzbare Funktionen nur das übergeben, was sie benötigen. Um die Entkopplung zu fördern, und Wiederverwendung von zusammensetzbaren Funktionen ist, sollte jede zusammensetzbare Funktion die geringste Menge an Informationen möglich sind.
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... MyDescendant(myViewModel.data) } // Don't pass the whole object! Just what the descendant needs. // Also, don't pass the ViewModel as an implicit dependency using // a CompositionLocal. @Composable fun MyDescendant(myViewModel: MyViewModel) { /* ... */ } // Pass only what the descendant needs @Composable fun MyDescendant(data: DataToDisplay) { // Display data }
Umkehrung der Kontrolle
Eine weitere Möglichkeit, die Übergabe unnötiger Abhängigkeiten an eine zusammensetzbare Funktion zu vermeiden, durch die Kontrollumkehr. Anstatt eine Abhängigkeit vom Nachfolger Logik ausführen, macht das übergeordnete Element dies stattdessen.
Im folgenden Beispiel wird gezeigt, wie ein Nachfolger die Anfrage auslösen muss, um Daten laden:
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... MyDescendant(myViewModel) } @Composable fun MyDescendant(myViewModel: MyViewModel) { Button(onClick = { myViewModel.loadData() }) { Text("Load data") } }
Je nach Fall kann MyDescendant
viel Verantwortung übernehmen. Außerdem
Wenn MyViewModel
als Abhängigkeit übergeben wird, ist MyDescendant
weniger wiederverwendbar, da
sind sie nun miteinander verbunden. Überlegen Sie, welche Alternative die
Abhängigkeit in die Nachfolgerelemente und wendet die Umkehrung der Kontrollprinzipien an,
macht den Ancestor für die Ausführung der Logik verantwortlich:
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... ReusableLoadDataButton( onLoadClick = { myViewModel.loadData() } ) } @Composable fun ReusableLoadDataButton(onLoadClick: () -> Unit) { Button(onClick = onLoadClick) { Text("Load data") } }
Dieser Ansatz eignet sich für einige Anwendungsfälle besser, da er die untergeordnetes Element von seinen unmittelbaren Vorgängern. Zusammensetzbare Funktionen mit Ancestors zugunsten flexibler zusammensetzbarer Funktionen auf unterer Ebene.
@Composable
Content-Lambdas können ebenfalls auf die gleiche Weise verwendet werden,
Vorteile:
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... ReusablePartOfTheScreen( content = { Button( onClick = { myViewModel.loadData() } ) { Text("Confirm") } } ) } @Composable fun ReusablePartOfTheScreen(content: @Composable () -> Unit) { Column { // ... content() } }
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Aufbau eines Designs in „Schreiben“
- Ansichten in „Compose“ verwenden
- Kotlin für Jetpack Compose