Architekturebenen in Jetpack Compose

Diese Seite bietet einen allgemeinen Überblick über die Architekturebenen, die Jetpack Compose und die Grundprinzipien, die diesem Design zugrunde liegen.

Jetpack Compose ist kein einzelnes monolithisches Projekt. wird er aus einer Zahl aus Modulen, die zu einem vollständigen Stapel zusammengefügt werden. Verständnis Die verschiedenen Module von Jetpack Compose ermöglichen Ihnen Folgendes:

  • Geeignete Abstraktionsebene verwenden, um Ihre App oder Bibliothek zu erstellen
  • Finden Sie heraus, wann Sie mit einem Dropdown-Menü auf eine niedrigere Ebene Anpassung
  • Abhängigkeiten minimieren

Ebenen

Die Hauptebenen von Jetpack Compose sind:

Abbildung 1: Die wichtigsten Ebenen von Jetpack Compose.

Jede Ebene baut auf den unteren Ebenen auf, wodurch verschiedene Funktionen übergeordneten Komponenten. Jede Ebene baut auf öffentlichen APIs der unteren Ebenen auf. um die Modulgrenzen zu überprüfen und Ebenen zu ersetzen, falls Sie die Sie brauchen. Untersuchen wir diese Ebenen von unten nach oben.

Laufzeit
In diesem Modul lernen Sie die Grundlagen der Compose-Laufzeit kennen: remember, mutableStateOf, die @Composable Anmerkung und SideEffect. Sie könnten direkt auf dieser Ebene aufbauen, wenn Sie Die Baumverwaltungsfunktionen von Compose, nicht die Benutzeroberfläche
Benutzeroberfläche
Die UI-Ebene besteht aus mehreren Modulen ( ui-text, ui-graphics, ui-tooling usw.). Diese Module implementieren die Grundlagen des UI-Toolkits, z. B. LayoutNode, Modifier, Eingabe-Handler, benutzerdefinierte Layouts und Zeichnungen. Sie könnten auf dieser Ebene aufbauen, brauchen Sie nur die grundlegenden Konzepte eines UI-Toolkits.
Grundlage
In diesem Modul lernen Sie unabhängige Bausteine für die Compose-UI, „Mag ich“-Bewertung Row und Column, LazyColumn Erkennung bestimmter Gesten usw. erwägen. Sie könnten erwägen, auf der um Ihr eigenes Designsystem zu erstellen.
Material
Dieses Modul veranschaulicht die Implementierung des Material Design-Systems für Benutzeroberfläche zum Erstellen von Elementen, Designsystem, Komponenten mit benutzerdefinierten Stilen, Welle Symbole. Bauen Sie auf dieser Ebene auf, wenn Sie Material Design in Ihrem App.

Designprinzipien

Ein Leitprinzip für Jetpack Compose besteht darin, Funktionen, die zusammengefügt (oder zusammengesetzt) werden können, anstatt einige wenige für monolithische Komponenten. Dieser Ansatz bietet eine Reihe von Vorteilen.

Umfassende Kontrolle

Komponenten auf höherer Ebene leisten in der Regel mehr für Sie, schränken jedoch die Menge an direkten die Sie haben. Wenn Sie mehr Kontrolle benötigen, können Sie das Drop-down-Menü eine niedrigerer Ebene.

Wenn Sie beispielsweise die Farbe einer Komponente animieren möchten, können Sie die Funktion animateColorAsState API:

val color = animateColorAsState(if (condition) Color.Green else Color.Red)

Wenn die Komponente jedoch immer grau sein soll, können Sie dies mit dieser API tun. Stattdessen können Sie im Drop-down-Menü die niedrigere Ebene verwenden. Animatable API:

val color = remember { Animatable(Color.Gray) }
LaunchedEffect(condition) {
    color.animateTo(if (condition) Color.Green else Color.Red)
}

Die übergeordnete animateColorAsState API basiert wiederum auf der niedrigeren Ebene. Animatable API verwenden. Die Verwendung der Low-Level-API ist komplexer, bietet jedoch mehr Steuerung. Wählen Sie die Abstraktionsebene, die Ihren Anforderungen am besten entspricht.

Personalisierung

Der Zusammenbau übergeordneter Komponenten aus kleineren Bausteinen und Komponenten einfacher anpassen können. Stellen Sie sich zum Beispiel die Implementierung von Button der Material-Ebene bereitgestellt wird:

@Composable
fun Button(
    // …
    content: @Composable RowScope.() -> Unit
) {
    Surface(/* … */) {
        CompositionLocalProvider(/* … */) { // set LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                Row(
                    // …
                    content = content
                )
            }
        }
    }
}

Ein Button besteht aus vier Komponenten:

  1. Ein Material Surface Hintergrund, Form, Klickhandhabung usw. angeben

  2. A CompositionLocalProvider wodurch der Alphawert des Inhalts geändert wird, wenn die Schaltfläche aktiviert oder deaktiviert ist

  3. A ProvideTextStyle legt den zu verwendenden Standardtextstil fest.

  4. Ein Row stellt die Standardlayoutrichtlinie für den Inhalt der Schaltfläche bereit

Wir haben einige Parameter und Kommentare ausgelassen, um die Struktur klarer zu machen. umfasst die gesamte Komponente nur etwa 40 Zeilen Code, diese vier Komponenten für die Schaltfläche zusammen. Komponenten wie Button sind unabhängig davon, welche Parameter sie offenlegen, Parameter, mit denen eine Komponente schwieriger zu nutzen ist. Materialkomponenten, z. B. die angegebenen Anpassungen im Material-Design-System integriert, sodass Material Design leicht zu befolgen ist. .

Wenn Sie jedoch eine Anpassung vornehmen möchten, die über die Parameter einer Komponente hinausgeht, können Sie das Drop-down-Menü eine Ebene und verzweigen eine Komponente. Beispiel: Material Das Design gibt an, dass Schaltflächen einen einfarbigen Hintergrund haben sollten. Wenn Sie benötigen einen Farbverlaufshintergrund. Diese Option wird vom Button nicht unterstützt. Parameter. In diesem Fall kannst du die Material Button-Implementierung als Referenzieren und erstellen Sie Ihre eigene Komponente:

@Composable
fun GradientButton(
    // …
    background: List<Color>,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(
                Brush.horizontalGradient(background)
            )
    ) {
        CompositionLocalProvider(/* … */) { // set material LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                content()
            }
        }
    }
}

Die obige Implementierung verwendet weiterhin Komponenten aus der Material-Ebene, wie die Konzepte von Material aktueller Content-Alpha und den aktuellen Textstil. Es ersetzt jedoch das Material Surface durch ein Row und gestaltet sie so, dass das gewünschte Erscheinungsbild erreicht wird.

Wenn Sie Material-Konzepte überhaupt nicht verwenden möchten, z. B. wenn Sie ein maßgeschneidertes Designsystem nutzen, Ebenenkomponenten:

@Composable
fun BespokeButton(
    // …
    backgroundColor: Color,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(backgroundColor)
    ) {
        // No Material components used
        content()
    }
}

Jetpack Compose reserviert die einfachsten Namen für die Komponenten der höchsten Ebene. Beispiel: androidx.compose.material.Text basiert auf androidx.compose.foundation.text.BasicText So können Sie für Ihre eigene Implementierung sichtbar ist, wenn Sie höhere Ebenen ersetzen möchten.

Die richtige Abstraktion auswählen

Dank der Philosophie von Compose beim Erstellen von mehrschichtigen, wiederverwendbaren Komponenten sollte nicht immer nach den Bausteinen der unteren Ebene greifen. Viele höhere Ebenen Komponenten bieten nicht nur mehr Funktionen, sondern implementieren auch häufig Best Practices z. B. die Unterstützung von Barrierefreiheit.

Wenn Sie Ihrer benutzerdefinierten Komponente beispielsweise Gestenunterstützung hinzufügen möchten, könnte es von Grund auf neu Modifier.pointerInput aber es gibt noch andere, übergeordnete Komponenten, die darauf aufbauen. bieten einen besseren Ausgangspunkt, Modifier.draggable, Modifier.scrollable oder Modifier.swipeable.

In der Regel sollten Sie auf der Komponente der höchsten Ebene aufbauen, die das die Sie benötigen, um von den Best Practices enthalten.

Weitere Informationen

Weitere Informationen finden Sie in der Jetsnack-Beispiel ein Beispiel für den Aufbau eines benutzerdefinierten Designsystems.