Modifikatoren für die Inhaltserstellung

Mit Modifikatoren können Sie ein Composeable verzieren oder ergänzen. Mit Modifikatoren Folgendes tun:

  • Größe, Layout, Verhalten und Darstellung des Composeables ändern
  • Informationen wie Labels für Bedienungshilfen hinzufügen
  • Nutzereingabe verarbeiten
  • Fügen Sie übergeordnete Interaktionen hinzu, indem Sie z. B. ein Element anklickbar, scrollbar, ziehbar oder zoombar

Modifikatoren sind standardmäßige Kotlin-Objekte. Erstellen Sie einen Modifikator, indem Sie eine der Klassenfunktionen Modifier aufrufen:

@Composable
private fun Greeting(name: String) {
    Column(modifier = Modifier.padding(24.dp)) {
        Text(text = "Hello,")
        Text(text = name)
    }
}

Zwei Textzeilen auf farbigem Hintergrund mit Innenabständen.

Sie können diese Funktionen verketten, um sie zusammenzusetzen:

@Composable
private fun Greeting(name: String) {
    Column(
        modifier = Modifier
            .padding(24.dp)
            .fillMaxWidth()
    ) {
        Text(text = "Hello,")
        Text(text = name)
    }
}

Der farbige Hintergrund hinter dem Text dehnt sich nun auf die gesamte Breite des Geräts aus.

Im obigen Code werden verschiedene Modifiziererfunktionen zusammen verwendet.

  • padding fügt einem Element einen Abstand hinzu.
  • Mit fillMaxWidth wird das zusammensetzbare Element auf die maximale Breite aufgefüllt, die ihm vom übergeordneten Element zugewiesen wurde.

Als Best Practice hat es sich bewährt, wenn alle zusammensetzbaren Funktionen einen modifier-Wert akzeptieren. und übergeben Sie diesen Modifikator an das erste untergeordnete Element, das UI ausgibt. Dadurch wird Ihr Code wiederverwendbarer und sein Verhalten vorhersehbarer und intuitiver. Für Weitere Informationen finden Sie in den Richtlinien für die Compose API, Elemente akzeptieren und respektieren ein Modifikatorparameter.

Reihenfolge der Modifikatoren ist wichtig

Die Reihenfolge der Modifikatorfunktionen ist erheblich. Da jede Funktion Änderungen an dem von der vorherigen Funktion zurückgegebenen Modifier vornimmt, wirkt sich die Reihenfolge auf das Endergebnis aus. Sehen wir uns ein Beispiel an:

@Composable
fun ArtistCard(/*...*/) {
    val padding = 16.dp
    Column(
        Modifier
            .clickable(onClick = onClick)
            .padding(padding)
            .fillMaxWidth()
    ) {
        // rest of the implementation
    }
}

Der gesamte Bereich, einschließlich des Abstands an den Rändern, reagiert auf Klicks.

Im Code oben ist der gesamte Bereich anklickbar, einschließlich des umgebenden Abstands, da der Modifikator padding nach dem Modifikator clickable angewendet wurde. Wenn die Reihenfolge der Modifikatoren umgekehrt ist, reagiert der durch padding hinzugefügte Abstand nicht auf Nutzereingaben:

@Composable
fun ArtistCard(/*...*/) {
    val padding = 16.dp
    Column(
        Modifier
            .padding(padding)
            .clickable(onClick = onClick)
            .fillMaxWidth()
    ) {
        // rest of the implementation
    }
}

Der Abstand am Rand des Layouts reagiert nicht mehr auf Klicks.

Integrierte Modifikatoren

Jetpack Compose bietet eine Liste mit integrierten Modifikatoren zum Dekorieren oder um eine zusammensetzbare Funktion zu erweitern. Im Folgenden finden Sie einige gängige Modifikatoren, mit denen Sie Ihre Layouts anpassen können.

padding und size

Standardmäßig werden in Compose bereitgestellte Layouts umgebrochen. Sie können jedoch mit dem Modifikator size eine Größe festlegen:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(/*...*/)
        Column { /*...*/ }
    }
}

Die von Ihnen angegebene Größe wird möglicherweise nicht berücksichtigt, wenn sie nicht den Einschränkungen des übergeordneten Elements des Layouts entspricht. Wenn Sie die zusammensetzbare Funktion Größe unabhängig von den eingehenden Einschränkungen festgelegt werden soll, verwenden Sie die Methode requiredSize. Modifikator:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(
            /*...*/
            modifier = Modifier.requiredSize(150.dp)
        )
        Column { /*...*/ }
    }
}

Das untergeordnete Image ist größer als die Einschränkungen des übergeordneten Images

In diesem Beispiel hat das Element Image eine Höhe von 150.dp, auch wenn das übergeordnete Element height auf 100.dp festgelegt ist, da der Modifikator requiredSize Vorrang hat.

Wenn ein untergeordnetes Layout die gesamte vom übergeordneten Layout zulässige Höhe einnehmen soll, fügen Sie den Modifikator fillMaxHeight hinzu. Compose bietet auch fillMaxSize und fillMaxWidth:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(
            /*...*/
            modifier = Modifier.fillMaxHeight()
        )
        Column { /*...*/ }
    }
}

Die Höhe des Bildes ist so groß wie das übergeordnete Bild.

Wenn Sie allen Seiten eines Elements einen Abstand hinzufügen möchten, legen Sie einen padding-Modifikator fest.

Wenn Sie über einer Textgrundlinie einen bestimmten Abstand vom oberen Rand des Layouts zur Grundlinie schaffen möchten, verwenden Sie den Modifikator paddingFromBaseline:

@Composable
fun ArtistCard(artist: Artist) {
    Row(/*...*/) {
        Column {
            Text(
                text = artist.name,
                modifier = Modifier.paddingFromBaseline(top = 50.dp)
            )
            Text(artist.lastSeenOnline)
        }
    }
}

Text mit Abstand darüber

Offset

Wenn Sie ein Layout relativ zu seiner ursprünglichen Position positionieren möchten, fügen Sie den Modifikator offset hinzu und legen Sie den Versatz auf der x- und y-Achse fest. Abweichungen können sowohl positiv als auch negativ sein. Der Unterschied zwischen padding und offset bedeutet, dass das Hinzufügen von offset zu einer zusammensetzbaren Funktion seine Maße ändern:

@Composable
fun ArtistCard(artist: Artist) {
    Row(/*...*/) {
        Column {
            Text(artist.name)
            Text(
                text = artist.lastSeenOnline,
                modifier = Modifier.offset(x = 4.dp)
            )
        }
    }
}

Text wurde auf die rechte Seite des übergeordneten Containers verschoben

Der offset-Modifikator wird horizontal entsprechend der Layoutrichtung angewendet. In einem rechtsläufigen Kontext verschiebt eine positive offset das Element während es in einem rechts nach links-Kontext das Element nach links verschiebt, Wenn Sie einen Versatz festlegen müssen, ohne die Layoutrichtung zu berücksichtigen, absoluteOffset Modifikator, bei dem ein positiver Offset-Wert das Element immer genau.

Der Modifikator offset hat zwei Überladungen: offset, bei der die Abweichungen als Parameter übergeben werden, und offset, bei der ein Lambda übergeben wird. Weitere Informationen dazu, wann Sie welche dieser Methoden verwenden und wie Sie die Leistung optimieren können, finden Sie im Abschnitt Leistung beim Erstellen von Compose-Aufrufen – Lesevorgänge so lange wie möglich verschieben.

Bereichssicherheit in Compose

In Compose gibt es Modifikatoren, die nur auf untergeordnete Elemente bestimmter Composeables angewendet werden können. Durch das Schreiben wird dies mithilfe von benutzerdefinierten Bereichen erzwungen.

Wenn Sie beispielsweise ein untergeordnetes Element so groß wie das übergeordnete Element Box machen möchten, ohne die Größe von Box zu beeinflussen, verwenden Sie den Modifikator matchParentSize. matchParentSize ist nur in BoxScope verfügbar. Daher kann es nur auf ein untergeordnetes Element innerhalb eines übergeordneten Box-Elements angewendet werden.

Die Bereichssicherheit verhindert, dass Sie Modifikatoren hinzufügen, die in anderen zusammensetzbare Funktionen und Bereiche und spart Zeit durch Ausprobieren.

Mithilfe von bereichsspezifischen Modifikatoren werden Eltern über bestimmte Informationen informiert, die sie über das Kind wissen sollten. Sie werden auch als Modifizierer für übergeordnete Daten bezeichnet. Ihre internen Strukturen unterscheiden sich vom allgemeinen Zweck. aber aus Nutzungssicht spielen diese Unterschiede keine Rolle.

matchParentSize in Box

Wie bereits erwähnt, können Sie mit dem Modifikator matchParentSize ein untergeordnetes Layout so anordnen, dass es dieselbe Größe wie das übergeordnete Box hat, ohne dass sich die Größe von Box ändert.

Hinweis: matchParentSize ist nur im Bereich Box verfügbar. Das bedeutet, dass es nur auf direkte untergeordnete Elemente von Box-Kompositen angewendet werden kann.

Im folgenden Beispiel übernimmt das untergeordnete Spacer-Element seine Größe vom übergeordneten Box-Element, das wiederum seine Größe von den größten Kindern abnimmt, ArtistCard.

@Composable
fun MatchParentSizeComposable() {
    Box {
        Spacer(
            Modifier
                .matchParentSize()
                .background(Color.LightGray)
        )
        ArtistCard()
    }
}

Behälter mit grauem Hintergrund

Wenn anstelle von matchParentSize fillMaxSize verwendet wird, nimmt Spacer den gesamten für das übergeordnete Element verfügbaren Platz ein, wodurch sich das übergeordnete Element ausdehnt und den gesamten verfügbaren Platz einnimmt.

Grauer Hintergrund, der den gesamten Bildschirm ausfüllt

weight in Row und Column

Wie Sie im vorherigen Abschnitt zu Abstand und Größe gesehen haben, wird die Größe eines Elements standardmäßig durch den Inhalt definiert, der umgebrochen wird. Sie können eine zusammensetzbare Größe so festlegen, dass sie innerhalb der übergeordnetes Element mit dem weight-Modifikator, der nur in RowScope verfügbar ist, und ColumnScope

Nehmen wir als Beispiel eine Row mit zwei Box-Kompositionen. Das erste Feld hat doppelt so viel weight wie das zweite, also doppelt so viel Breite. Da Row 210.dp breit ist, ist der erste Box 140.dp breit und Die zweite ist 70.dp:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.fillMaxWidth()
    ) {
        Image(
            /*...*/
            modifier = Modifier.weight(2f)
        )
        Column(
            modifier = Modifier.weight(1f)
        ) {
            /*...*/
        }
    }
}

Das Bild entspricht der doppelten Textbreite

Modifikatoren extrahieren und wiederverwenden

Mehrere Modifikatoren können miteinander verknüpft werden, um ein Composeable zu verzieren oder zu ergänzen. Diese Kette wird über die Modifier-Schnittstelle erstellt, die eine sortierte, unveränderliche Liste einzelner Modifier.Elements darstellt.

Jedes Modifier.Element steht für ein individuelles Verhalten, z. B. für das Layout, das Zeichnen und die Grafik, alle gestenbezogenen, Fokus- und semantischen Verhaltensweisen sowie Geräteeingabeereignisse. Die Reihenfolge ist wichtig: Modifizierelemente, die zuerst hinzugefügt werden, werden zuerst angewendet.

Manchmal kann es vorteilhaft sein, dieselben Modifikatorketteninstanzen in mehrerer zusammensetzbarer Elemente, indem sie sie in Variablen extrahieren und in die einen höheren Umfang haben. Dies kann aus mehreren Gründen dazu beitragen, die Lesbarkeit des Codes oder die Leistung Ihrer App zu verbessern:

  • Die Neuzuweisung der Modifikatoren wird nicht wiederholt, wenn für Composables, in denen sie verwendet werden, eine Neuzusammensetzung erfolgt.
  • Modifikatorketten könnten sehr lang und komplex sein. Dieselbe Instanz einer Kette kann den Aufwand für die Arbeitslast verringern, die die Compose-Laufzeit wenn Sie sie vergleichen,
  • Diese Extraktion fördert die Sauberkeit, Konsistenz und Verwaltbarkeit des Codes in der gesamten Codebasis

Best Practices für die Wiederverwendung von Modifizierern

Erstellen Sie Ihre eigenen Modifier-Ketten und extrahieren Sie sie, um sie in mehreren zusammensetzbaren Komponenten. Es ist völlig in Ordnung, nur einen Modifizierer zu speichern, sind datenähnliche Objekte:

val reusableModifier = Modifier
    .fillMaxWidth()
    .background(Color.Red)
    .padding(12.dp)

Modifikatoren bei häufig wechselndem Status extrahieren und wiederverwenden

Bei der Beobachtung, dass sich der Status innerhalb von zusammensetzbaren Funktionen häufig ändert, z. B. Animation oder scrollState, kann eine erhebliche Anzahl von Neuzusammensetzungen fertig. In diesem Fall werden Ihre Modifier bei jeder Neuzusammensetzung und potenziell für jeden Frame zugewiesen:

@Composable
fun LoadingWheelAnimation() {
    val animatedState = animateFloatAsState(/*...*/)

    LoadingWheel(
        // Creation and allocation of this modifier will happen on every frame of the animation!
        modifier = Modifier
            .padding(12.dp)
            .background(Color.Gray),
        animatedState = animatedState
    )
}

Stattdessen können Sie dieselbe Instanz des Modifiers erstellen, extrahieren und wiederverwenden und sie so an das Composeable übergeben:

// Now, the allocation of the modifier happens here:
val reusableModifier = Modifier
    .padding(12.dp)
    .background(Color.Gray)

@Composable
fun LoadingWheelAnimation() {
    val animatedState = animateFloatAsState(/*...*/)

    LoadingWheel(
        // No allocation, as we're just reusing the same instance
        modifier = reusableModifier,
        animatedState = animatedState
    )
}

Modifikatoren ohne Bereich extrahieren und wiederverwenden

Modifikatoren können auf einen bestimmten Geltungsbereich oder auf einen bestimmten zusammensetzbar sind. Modifikatoren ohne Geltungsbereich können ganz einfach extrahiert werden. außer den zusammensetzbaren Funktionen als einfache Variablen verwenden:

val reusableModifier = Modifier
    .fillMaxWidth()
    .background(Color.Red)
    .padding(12.dp)

@Composable
fun AuthorField() {
    HeaderText(
        // ...
        modifier = reusableModifier
    )
    SubtitleText(
        // ...
        modifier = reusableModifier
    )
}

Das ist besonders in Kombination mit Lazy-Layouts von Vorteil. In den meisten Fällen sollten alle Ihre Artikel, die möglicherweise sehr zahlreich sind, genau dieselben Modifikatoren haben:

val reusableItemModifier = Modifier
    .padding(bottom = 12.dp)
    .size(216.dp)
    .clip(CircleShape)

@Composable
private fun AuthorList(authors: List<Author>) {
    LazyColumn {
        items(authors) {
            AsyncImage(
                // ...
                modifier = reusableItemModifier,
            )
        }
    }
}

Modifikatoren mit Bereich extrahieren und wiederverwenden

Wenn Sie mit Modifikatoren arbeiten, die auf bestimmte Composeables beschränkt sind, können Sie sie auf die höchstmögliche Ebene extrahieren und bei Bedarf wiederverwenden:

Column(/*...*/) {
    val reusableItemModifier = Modifier
        .padding(bottom = 12.dp)
        // Align Modifier.Element requires a ColumnScope
        .align(Alignment.CenterHorizontally)
        .weight(1f)
    Text1(
        modifier = reusableItemModifier,
        // ...
    )
    Text2(
        modifier = reusableItemModifier
        // ...
    )
    // ...
}

Sie sollten nur die extrahierten Bereichsmodifikatoren an den direkte untergeordnete Elemente des gleichen Bereichs. Siehe Abschnitt Sicherheit des Umfangs in Schreiben Sie, um mehr darüber zu erfahren, warum das wichtig ist:

Column(modifier = Modifier.fillMaxWidth()) {
    // Weight modifier is scoped to the Column composable
    val reusableItemModifier = Modifier.weight(1f)

    // Weight will be properly assigned here since this Text is a direct child of Column
    Text1(
        modifier = reusableItemModifier
        // ...
    )

    Box {
        Text2(
            // Weight won't do anything here since the Text composable is not a direct child of Column
            modifier = reusableItemModifier
            // ...
        )
    }
}

Weitere Verknüpfung der extrahierten Modifikatoren

Sie können die extrahierten Modifikatorketten weiter verketten oder anhängen, indem Sie die Methode .then()-Funktion:

val reusableModifier = Modifier
    .fillMaxWidth()
    .background(Color.Red)
    .padding(12.dp)

// Append to your reusableModifier
reusableModifier.clickable { /*...*/ }

// Append your reusableModifier
otherModifier.then(reusableModifier)

Beachte dabei aber, dass die Reihenfolge der Modifikatoren wichtig ist.

Weitere Informationen

Wir stellen eine vollständige Liste der Modifikatoren bereit, mit ihre Parameter und Bereiche.

Weitere Übungen zur Verwendung von Modifikatoren finden Sie im Codelab zu grundlegenden Layouts in Compose oder im Repository „Jetzt in Android“.

Weitere Informationen zu benutzerdefinierten Modifikatoren und deren Erstellung finden Sie in der Dokumentation unter Benutzerdefinierte Layouts – Layout-Modifikator verwenden.