Modifikatoren für die Inhaltserstellung

Mit Modifikatoren können Sie ein zusammensetzbares Element dekorieren oder erweitern. Modifikatoren ermöglichen Ihnen Folgendes:

  • Größe, Layout, Verhalten und Darstellung des zusammensetzbaren Elements ändern
  • Informationen wie Labels für die Barrierefreiheit hinzufügen
  • Nutzereingaben verarbeiten
  • Interaktionen auf hoher Ebene hinzufügen, z. B. ein Element anklickbar, scrollbar, ziehbar oder zoombar machen

Modifikatoren sind Standard-Kotlin-Objekte. Sie erstellen einen Modifikator, indem Sie eine der Modifier Klassenfunktionen aufrufen:

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

Zwei Textzeilen auf einem farbigen Hintergrund mit Innenabstand um den Text.

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 erstreckt sich jetzt über die gesamte Breite des Geräts.

Im obigen Code werden verschiedene Modifikatorfunktionen zusammen verwendet.

  • padding fügt um ein Element herum Leerraum ein.
  • fillMaxWidth bewirkt, dass das zusammensetzbare Element die maximale Breite einnimmt, die ihm vom übergeordneten Element zugewiesen wurde.

Es ist eine Best Practice, dass alle zusammensetzbaren Elemente einen modifier-Parameter akzeptieren und diesen Modifikator an das erste untergeordnete Element übergeben, das UI ausgibt. Dadurch wird Ihr Code wiederverwendbarer und sein Verhalten vorhersehbarer und intuitiver. Weitere Informationen finden Sie in den Compose API-Richtlinien unter Elements accept and respect a Modifier parameter.

Reihenfolge der Modifikatoren ist wichtig

Die Reihenfolge der Modifikatorfunktionen ist wichtig. Da jede Funktion Änderungen am Modifier vornimmt, der von der vorherigen Funktion zurückgegeben wird, wirkt sich die Reihenfolge auf das Endergebnis aus. Hier ein Beispiel:

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

Die gesamte Fläche, einschließlich des Innenabstands an den Rändern, reagiert auf Klicks.

Im obigen Code ist der gesamte Bereich anklickbar, einschließlich des umgebenden Leerraums, da der padding-Modifikator nach dem clickable-Modifikator angewendet wurde. Wenn die Reihenfolge der Modifikatoren umgekehrt ist, reagiert der von padding hinzugefügte Leerraum 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 integrierter Modifikatoren, mit denen Sie ein zusammensetzbares Element dekorieren oder erweitern können. Hier sind einige gängige Modifikatoren, mit denen Sie Ihre Layouts anpassen können.

padding und size

Standardmäßig umschließen in Compose bereitgestellte Layouts ihre untergeordneten Elemente. Sie können jedoch mit dem size Modifikator 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 Layouts entspricht. Wenn die Größe des zusammensetzbaren Elements unabhängig von den eingehenden Einschränkungen festgelegt sein soll, verwenden Sie den Modifikator requiredSize:

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

Das untergeordnete Bild ist größer als die Einschränkungen des übergeordneten Bildes.

In diesem Beispiel ist die height des übergeordneten Elements auf 100.dp festgelegt, die Höhe des Image beträgt jedoch 150.dp, da der Modifikator requiredSize Vorrang hat.

Wenn ein untergeordnetes Layout die gesamte verfügbare Höhe einnehmen soll, die vom übergeordneten Element zugelassen wird, 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 entspricht der Höhe des übergeordneten Elements.

Wenn Sie um ein Element herum Leerraum hinzufügen möchten, legen Sie einen padding-Modifikator fest.

Wenn Sie über einer Text-Baseline Leerraum hinzufügen möchten, um einen bestimmten Abstand vom oberen Rand des Layouts zur Baseline zu erzielen, 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 offset Modifikator hinzu und legen Sie den Offset auf der x - und y -Achse fest. Offsets können positiv oder nicht positiv sein. Der Unterschied zwischen padding und offset besteht darin, dass das Hinzufügen eines offset zu einem zusammensetzbaren Element seine Maße nicht ändert:

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

Text nach rechts vom übergeordneten Container verschoben

Der Modifikator offset wird horizontal entsprechend der Layoutrichtung angewendet. In einem von links nach rechts ausgerichteten Kontext verschiebt ein positiver offset das Element nach rechts, während es in einem von rechts nach links ausgerichteten Kontext nach links verschoben wird. Wenn Sie einen Offset festlegen müssen, ohne die Layoutrichtung zu berücksichtigen, verwenden Sie den absoluteOffset Modifikator. Hier verschiebt ein positiver Offsetwert das Element immer nach rechts.

Der offset Modifikator bietet zwei Überladungen: offset, das die Offsets als Parameter verwendet, und offset, das eine Lambda-Funktion verwendet. Weitere Informationen dazu, wann Sie welche Überladung verwenden sollten und wie Sie die Leistung optimieren können, finden Sie im Abschnitt Compose-Leistung – Lesevorgänge so lange wie möglich verzögern.

Bereichssicherheit in Compose

In Compose gibt es Modifikatoren, die nur verwendet werden können, wenn sie auf untergeordnete Elemente bestimmter zusammensetzbarer Elemente angewendet werden. Compose erzwingt dies mithilfe benutzerdefinierter Bereiche.

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

Die Bereichssicherheit verhindert, dass Sie Modifikatoren hinzufügen, die in anderen zusammensetzbaren Elementen und Bereichen nicht funktionieren würden. So sparen Sie Zeit durch Ausprobieren.

Bereichsbezogene Modifikatoren benachrichtigen das übergeordnete Element über Informationen, die es über das untergeordnete Element wissen sollte. Sie werden auch häufig als Modifikatoren für übergeordnete Daten bezeichnet. Ihre Interna unterscheiden sich von den Modifikatoren für allgemeine Zwecke, aber aus Nutzungssicht spielen diese Unterschiede keine Rolle.

matchParentSize in Box

Wie oben erwähnt, verwenden Sie den Modifikator matchParentSize, wenn ein untergeordnetes Layout dieselbe Größe wie ein übergeordnetes Box haben soll, ohne die Größe von Box zu beeinflussen.

matchParentSize ist nur innerhalb eines Box-Bereichs verfügbar. Das bedeutet, dass es nur auf direkte untergeordnete Elemente von Box-zusammensetzbaren Elementen angewendet wird.

Im folgenden Beispiel übernimmt das untergeordnete Spacer seine Größe vom übergeordneten Box, das wiederum seine Größe von den größten untergeordneten Elementen übernimmt, in diesem Fall ArtistCard.

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

Grauer Hintergrund, der den Container ausfüllt

Wenn fillMaxSize anstelle von matchParentSize verwendet würde, würde das Spacer den gesamten verfügbaren Platz einnehmen, der dem übergeordneten Element zugewiesen ist. Dadurch würde sich das übergeordnete Element erweitern und den gesamten verfügbaren Platz einnehmen.

Grauer Hintergrund, der den Bildschirm ausfüllt

weight in Row und Column

Wie Sie im vorherigen Abschnitt zu Leerraum und Größe gesehen haben, wird die Größe eines zusammensetzbaren Elements standardmäßig durch den Inhalt definiert, den es umschließt. Sie können die Größe eines zusammensetzbaren Elements so festlegen, dass sie innerhalb des übergeordneten Elements flexibel ist. Verwenden Sie dazu den Modifikator weight, der nur in RowScope und ColumnScope verfügbar ist.

Nehmen wir eine Row, die zwei Box-zusammensetzbare Elemente enthält. Das erste Feld hat das doppelte weight des zweiten Felds, also die doppelte Breite. Da die Row 210.dp breit ist, ist das erste Box 140.dp breit und das zweite 70.dp:

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

Die Bildbreite ist doppelt so groß wie die Textbreite.

Modifikatoren extrahieren und wiederverwenden

Mehrere Modifikatoren können verkettet werden, um eine zusammensetzbare Funktion zu dekorieren oder zu erweitern. Diese Kette wird über die Modifier Schnittstelle die eine geordnete, unveränderliche Liste einzelner Modifier.Elements darstellt.

Jedes Modifier.Element stellt ein einzelnes Verhalten dar, z. B. Layout-, Zeichen- und Grafikverhalten, alle gestenbezogenen Verhaltensweisen, Fokus- und Semantikverhalten sowie Geräteeingabeereignisse. Die Reihenfolge ist wichtig: Modifikatorelemente, die zuerst hinzugefügt werden, werden zuerst angewendet.

Manchmal kann es sinnvoll sein, dieselben Modifikatorketteninstanzen in mehreren zusammensetzbaren Elementen wiederzuverwenden. Dazu werden sie in Variablen extrahiert und in höhere Bereiche verschoben. Das kann die Lesbarkeit des Codes verbessern oder die Leistung Ihrer App aus mehreren Gründen steigern:

  • Die Neuzuweisung der Modifikatoren wird bei der Neuzusammensetzung für zusammensetzbare Elemente, die sie verwenden, nicht wiederholt.
  • Modifikatorketten können sehr lang und komplex sein. Wenn Sie dieselbe Instanz einer Kette wiederverwenden, kann die Arbeitslast der Compose-Laufzeit beim Vergleich reduziert werden.
  • Diese Extraktion fördert die Übersichtlichkeit, Konsistenz und Wartbarkeit des Codes in der gesamten Codebasis.

Best Practices für die Wiederverwendung von Modifikatoren

Erstellen Sie eigene Modifier-Ketten und extrahieren Sie sie, um sie in mehreren zusammensetzbaren Komponenten wiederzuverwenden. Sie können einen Modifikator einfach speichern, da es sich um datenähnliche Objekte handelt:

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

Modifikatoren extrahieren und wiederverwenden, wenn häufig geänderter Status beobachtet wird

Wenn häufig geänderte Status in zusammensetzbaren Elementen beobachtet werden, z. B. Animationsstatus oder scrollState, kann es zu einer erheblichen Anzahl von Neuzusammensetzungen kommen. In diesem Fall werden Ihre Modifikatoren bei jeder Neuzusammensetzung und möglicherweise 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 Modifikators erstellen, extrahieren und wiederverwenden und sie so an das zusammensetzbare Element ü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 ohne Bereich oder auf ein bestimmtes zusammensetzbares Element beschränkt sein. Bei Modifikatoren ohne Bereich können Sie sie ganz einfach außerhalb von zusammensetzbaren Elementen als einfache Variablen extrahieren:

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

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

Das kann besonders in Kombination mit Lazy-Layouts von Vorteil sein. In den meisten Fällen sollten alle Ihre Elemente, die möglicherweise eine erhebliche Anzahl haben, 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 zusammensetzbare Elemente 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 die extrahierten, bereichsbezogenen Modifikatoren nur an direkte untergeordnete Elemente mit demselben Bereich übergeben. Weitere Informationen dazu, warum das wichtig ist, finden Sie im Abschnitt Bereichssicherheit in Compose:

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 Verkettung extrahierter Modifikatoren

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

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

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

// Append your reusableModifier
otherModifier.then(reusableModifier)

Denken Sie daran, dass die Reihenfolge der Modifikatoren wichtig ist!

Weitere Informationen

Wir bieten eine vollständige Liste der Modifikatoren mit ihren Parametern und Bereichen.

Weitere Übungen zur Verwendung von Modifikatoren finden Sie im Codelab Basic layouts in Compose oder im Now in Android-Repository.

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