Modifikatoren für die Inhaltserstellung

Mithilfe von Modifikatoren können Sie zusammensetzbare Funktionen dekorieren oder erweitern. Mit Modifikatoren Folgendes tun:

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

Modifikatoren sind Kotlin-Standardobjekte. Erstellen Sie einen Modifizierer, indem Sie eine der Modifier-Klassenfunktionen:

@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 Modifikatorfunktionen zusammen verwendet.

  • padding platziert ein Element mit Platz.
  • Mit fillMaxWidth wird für die zusammensetzbare Füllung die maximale Breite festgelegt, die von in das übergeordnete Element ein.

Als Best Practice wird empfohlen, dass alle zusammensetzbaren Funktionen einen modifier-Wert akzeptieren. und übergeben Sie diesen Modifikator an das erste untergeordnete Element, das UI ausgibt. Dadurch werden Ihre und macht 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.

Die Reihenfolge der Modifikatoren ist wichtig

Die Reihenfolge der Modifikatorfunktionen ist erheblich. Da jede Funktion ändert sich zu der Modifier, die von der vorherigen Funktion zurückgegeben wurde, die Sequenz das Endergebnis beeinflusst. Sehen wir uns dazu 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 darüber ist der gesamte Bereich anklickbar, einschließlich des umgebenden Bereichs Abstand, da der padding-Modifikator nach clickable angewendet wurde Modifikator. Wenn die Reihenfolge der Modifikatoren umgekehrt ist, gilt das von padding hinzugefügte Leerzeichen nicht auf Nutzereingaben reagieren:

@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. Hier sind einige gängige Modifikatoren, mit denen Sie Ihre Layouts.

padding und size

Standardmäßig umschließen die untergeordneten Layouts in der Funktion „Schreiben“. Sie können jedoch können Sie eine Größe mit dem size-Modifikator festlegen:

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

Beachten Sie, dass die angegebene Größe möglicherweise nicht berücksichtigt wird, wenn sie nicht die vom übergeordneten Element des Layouts stammenden Einschränkungen. 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

Selbst wenn das übergeordnete Element height auf 100.dp festgelegt ist, wird die Höhe des Elements Der Image ist 150.dp, da der Modifikator requiredSize Vorrang.

Wenn ein untergeordnetes Layout die gesamte verfügbare Höhe ausfüllen soll, übergeordnetes Element den fillMaxHeight-Modifikator hinzu. 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 ein Element vollständig mit Innenrand versehen möchten, legen Sie einen padding-Modifikator fest.

Wenn Sie über einer Textbasis einen Abstand hinzufügen möchten, Abstand vom oberen Rand des Layouts zur Grundlinie festgelegt haben, verwenden Sie paddingFromBaseline-Modifikator:

@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

Um ein Layout relativ zu seiner ursprünglichen Position zu positionieren, fügen Sie den offset und legen Sie den Versatz auf der x- und y-Achse fest. Offsets können sowohl positiv als auch nicht positiv 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 offset-Modifikator erzeugt zwei Überlastungen: offset, Offsets als Parameter und offset, die eine Lambda-Funktion annimmt. Detailliertere Informationen zur Verwendung und Optimierung finden Sie in den Compose-Leistung – Lesevorgänge so lange wie möglich zurückstellen:

Bereichssicherheit in Compose

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

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

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

Mit auf einen Bereich reduzierten Modifikatoren werden Eltern über bestimmte Informationen informiert. über das Kind wissen sollten. Sie werden auch als Modifikatoren für übergeordnete Daten. Ihre internen Strukturen unterscheiden sich vom allgemeinen Zweck. aber aus Sicht der Nutzung spielen diese Unterschiede keine Rolle.

matchParentSize in Box

Wenn Sie möchten, dass ein untergeordnetes Layout dieselbe Größe wie ein übergeordnetes Element hat, Box, ohne die Größe von Box zu beeinflussen, verwenden Sie den matchParentSize-Modifikator.

matchParentSize ist nur im Bereich Box verfügbar. Das bedeutet, sie gilt nur für direkte untergeordnete Elemente von Box zusammensetzbaren Funktionen.

Im folgenden Beispiel übernimmt das untergeordnete Spacer-Element seine Größe von seinem ü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 fillMaxSize statt matchParentSize verwendet wird, würde Spacer verwendet wird. Dies führt dazu, dass maximiert werden und den gesamten verfügbaren Bereich ausfüllen.

Grauer Hintergrund füllt den Bildschirm

weight in Row und Column

Wie Sie bereits im vorherigen Abschnitt über Abstände und Größe ist, wird standardmäßig eine zusammensetzbare Größe durch das umschlossene Inhalte. Sie können eine zusammensetzbare Größe so festlegen, dass sie innerhalb der das übergeordnete Element mit dem weight-Modifikator, der nur in RowScope verfügbar ist, und ColumnScope

Nehmen wir ein Row, das zwei zusammensetzbare Box-Elemente enthält. Das erste Feld wird doppelt so viele weight wie das zweite Feld, also doppelt so oft wie das zweite Feld, erhalten. 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 verkettet werden, um um eine zusammensetzbare Funktion zu erweitern. Diese Kette wird über die Schnittstelle Modifier erstellt die eine geordnete, unveränderliche Liste mit einzelnen Modifier.Elements darstellt.

Jedes Modifier.Element steht für ein individuelles Verhalten wie Layout, Zeichnung alle gesten-, Fokus- und semantischen Verhaltensweisen, und Geräteeingabeereignisse. Ihre Reihenfolge ist wichtig: Modifikatorelemente, werden zuerst angewendet.

Manchmal kann es vorteilhaft sein, dieselben Modifikatorketteninstanzen in mehrerer zusammensetzbarer Elemente, indem sie sie in Variablen extrahieren und in auf höheren Ebenen. Sie kann die Lesbarkeit von Code oder aus verschiedenen Gründen:

  • Die Neuzuweisung der Modifikatoren wird bei einer Neuzusammensetzung nicht wiederholt. für zusammensetzbare Funktionen verwenden,
  • 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)

Modifizierer extrahieren und wiederverwenden, wenn sich der Zustand häufig ändert

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 Modifikatoren bei jeder Neuzusammensetzung und möglicherweise für jeden Frame:

@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 übergeben es wie folgt an die zusammensetzbare Funktion:

// 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. 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 Hüllen möchten Sie, dass alle Ihre potenziell erhebliche Menge an Elementen dieselben Modifikatoren verwendet werden:

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

Bereichsmodifikatoren extrahieren und wiederverwenden

Wenn Sie mit Modifikatoren arbeiten, die auf bestimmte zusammensetzbare Funktionen beschränkt sind, können Sie extrahieren Sie sie so weit wie möglich und verwenden Sie sie bei Bedarf wieder:

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 Verkettung extrahierter 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 in den Grundlegende Layouts im Codelab zu „Compose“ oder im Jetzt im Android-Repository.

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