Einschränkungen und Modifikatorreihenfolge

In Compose können Sie mehrere Modifikatoren miteinander verketten, um das Erscheinungsbild einer zusammensetzbaren Funktion zu ändern. Diese Modifikatorketten können die Einschränkungen beeinflussen, die an zusammensetzbare Funktionen übergeben werden und die Grenzen für Breite und Höhe definieren.

Auf dieser Seite wird beschrieben, wie verkettete Modifikatoren Einschränkungen und damit die Messung und Platzierung von zusammensetzbaren Funktionen beeinflussen.

Modifikatoren in der Struktur der Benutzeroberfläche

Um zu verstehen, wie sich Modifikatoren gegenseitig beeinflussen, ist es hilfreich, sich vorzustellen, wie sie im UI-Baum erscheinen, der in der Kompositionphase generiert wird. Weitere Informationen finden Sie im Abschnitt Komposition.

In der UI-Struktur können Sie Modifikatoren als Wrapper-Knoten für die Layoutknoten visualisieren:

Code für Composeables und Modifikatoren sowie deren visuelle Darstellung als UI-Baum.
Abbildung 1. Modifikatoren, die Layoutknoten in der Baumstruktur der Benutzeroberfläche zusammenfassen.

Wenn du einem Composeable mehrere Modifikatoren hinzufügst, entsteht eine Kette von Modifikatoren. Wenn Sie mehrere Modifikatoren verketten, umschließt jeder Modifikatorknoten den Rest der Kette und den Layoutknoten darin. Wenn Sie beispielsweise einen clip- und einen size-Modifikator verketten, umschließt der clip-Modifikatorknoten den size-Modifikatorknoten, der dann den Image-Layoutknoten umschließt.

In der Layoutphase bleibt der Algorithmus, der den Baum durchläuft, gleich, aber auch jeder Modifikatorknoten wird besucht. So kann ein Modifikator die Größenanforderungen und die Platzierung des Modifikators oder Layoutknotens ändern, um den Text einzufügen.

Wie in Abbildung 2 dargestellt, besteht die Implementierung der Image- und Text-Kompositen aus einer Kette von Modifikatoren, die einen einzelnen Layoutknoten umschließen. Die Implementierungen von Row und Column sind einfach Layoutknoten, die beschreiben, wie ihre untergeordneten Elemente angeordnet werden.

Die Baumstruktur von vorhin, aber jetzt ist jeder Knoten nur ein einfaches Layout mit vielen Modifikatoren, die Knoten umgeben.
Abbildung 2: Dieselbe Baumstruktur wie in Abbildung 1, aber mit den zusammensetzbaren Funktionen im UI-Baum, dargestellt als Ketten von Modifikatoren.

Zusammenfassung:

  • Modifikatoren schließen einen einzelnen Modifikator oder Layoutknoten ein.
  • Layoutknoten können mehrere untergeordnete Knoten anordnen.

In den folgenden Abschnitten wird beschrieben, wie Sie dieses mentale Modell zur Erläuterung der Modifikatorverkettung verwenden und wie es die Größe der zusammensetzbaren Funktionen beeinflusst.

Einschränkungen in der Layoutphase

In der Layoutphase wird mit einem dreistufigen Algorithmus die Breite, Höhe und die X‑ und Y‑Koordinaten jedes Layoutknotens ermittelt:

  1. Untergeordnete Elemente messen: Ein Knoten misst seine untergeordneten Elemente, falls vorhanden.
  2. Eigene Größe festlegen: Anhand dieser Messungen entscheidet ein Knoten über seine eigene Größe.
  3. Untergeordnete Elemente platzieren: Jeder untergeordnete Knoten wird relativ zur Position eines Knotens platziert.

Constraints helfen Ihnen, in den ersten beiden Schritten des Algorithmus die richtigen Größen für die Knoten zu finden. Einschränkungen definieren die Mindest- und Höchstgrenzen für die Breite und Höhe eines Knotens. Wenn der Knoten über seine Größe entscheidet, sollte seine gemessene Größe in diesen Größenbereich fallen.

Arten von Einschränkungen

Eine Einschränkung kann eine der folgenden sein:

  • Begrenzt: Der Knoten hat eine maximale und minimale Breite und Höhe.
Begrenzte Einschränkungen verschiedener Größen innerhalb eines Containers.
Abbildung 3 Begrenzte Einschränkungen.
  • Unbegrenzt: Die Größe des Knotens ist nicht begrenzt. Die maximalen Werte für Breite und Höhe sind auf unendlich festgelegt.
Unbegrenzte Einschränkungen, bei denen Breite und Höhe auf unendlich festgelegt sind. Die Einschränkungen gehen über den Container hinaus.
Abbildung 4 Unbeschränkte Einschränkungen.
  • Genau: Der Knoten muss genau einer bestimmten Größe entsprechen. Die Mindest- und Höchstgrenzen sind auf denselben Wert festgelegt.
Genaue Einschränkungen, die einer genauen Größenanforderung innerhalb des Containers entsprechen.
Abbildung 5 Genaue Einschränkungen.
  • Kombination: Der Knoten folgt einer Kombination der oben genannten Einschränkungstypen. Eine Einschränkung könnte beispielsweise die Breite begrenzen und gleichzeitig eine unbegrenzte maximale Höhe zulassen oder eine genaue Breite festlegen, aber eine begrenzte Höhe angeben.
Zwei Container mit Kombinationen aus begrenzten und unbegrenzten Einschränkungen sowie genauen Breiten und Höhen.
Abbildung 6 Kombinationen von begrenzten und unbegrenzten Einschränkungen sowie exakter Breite und Höhe.

Im nächsten Abschnitt wird beschrieben, wie diese Einschränkungen von einem übergeordneten Element an ein untergeordnetes Element übergeben werden.

So werden Einschränkungen von übergeordneten auf untergeordnete Elemente übergeben

Im ersten Schritt des Algorithmus, der unter Einschränkungen in der Layoutphase beschrieben wird, werden Einschränkungen im UI-Baum von übergeordneten Elementen an untergeordnete Elemente weitergegeben.

Wenn ein übergeordneter Knoten seine untergeordneten Knoten misst, stellt er diese Einschränkungen für jedes untergeordnete Element bereit, um es darüber zu informieren, wie groß oder klein sie sein dürfen. Wenn es dann seine eigene Größe festlegt, hält es sich auch an die Einschränkungen, die von seinen übergeordneten Elementen übergeben wurden.

Der Algorithmus funktioniert im Groben so:

  1. Um die tatsächliche Größe zu bestimmen, misst der Stammknoten im UI-Baum seine untergeordneten Elemente und leitet dieselben Einschränkungen an sein erstes untergeordnetes Element weiter.
  2. Wenn das untergeordnete Element ein Modifikator ist, der sich nicht auf die Messung auswirkt, werden die Einschränkungen an den nächsten Modifikator weitergeleitet. Die Einschränkungen werden unverändert an die Modifikatorkette übergeben, es sei denn, ein Modifikator wird erreicht, der sich auf die Analyse auswirkt. Die Einschränkungen werden dann entsprechend neu skaliert.
  3. Sobald ein Knoten erreicht wird, der keine untergeordneten Knoten hat (dies wird als „Blattknoten“ bezeichnet), wird seine Größe anhand der übergebenen Einschränkungen festgelegt und an das übergeordnete Element zurückgegeben.
  4. Das übergeordnete Element passt seine Einschränkungen anhand der Messungen dieses untergeordneten Elements an und ruft sein nächstes untergeordnetes Element mit diesen angepassten Einschränkungen auf.
  5. Sobald alle untergeordneten Elemente eines übergeordneten Elements gemessen wurden, entscheidet der übergeordnete Knoten über seine eigene Größe und teilt dies seinem übergeordneten Element mit.
  6. So wird der gesamte Baum zuerst von oben nach unten durchlaufen. Schließlich haben sich alle Knoten für ihre Größe entschieden und der Messschritt ist abgeschlossen.

Ein ausführliches Beispiel finden Sie im Video Einschränkungen und Reihenfolge der Modifikatoren.

Modifikatoren, die sich auf Einschränkungen auswirken

Im vorherigen Abschnitt haben Sie gelernt, dass sich einige Modifikatoren auf die Größe der Einschränkung auswirken können. In den folgenden Abschnitten werden bestimmte Modifikatoren beschrieben, die sich auf Einschränkungen auswirken.

size-Modifikator

Mit dem Modifikator size wird die bevorzugte Größe der Inhalte angegeben.

Beispielsweise sollte der folgende UI-Baum in einem Container mit 300dp × 200dp gerendert werden. Die Einschränkungen sind begrenzt. Die Breite darf zwischen 100dp und 300dp liegen und die Höhe zwischen 100dp und 200dp:

Ein Teil eines UI-Baums mit dem Größenmodifikator, der einen Layoutknoten umschließt, und die Darstellung der durch den Größenmodifikator in einem Container festgelegten Begrenzungen.
Abbildung 7. Begrenzte Einschränkungen im UI-Baum und ihre Darstellung in einem Container.

Mit dem Modifikator size werden eingehende Einschränkungen an den übergebenen Wert angepasst. In diesem Beispiel ist der Wert 150dp:

Entspricht Abbildung 7, mit dem Unterschied, dass der Größenmodifikator eingehende Einschränkungen an den übergebenen Wert anpasst.
Abbildung 8. Der size-Modifikator, mit dem Einschränkungen an 150dp angepasst werden.

Wenn die Breite und Höhe kleiner als die kleinste Einschränkungsgrenze oder größer als die größte Einschränkungsgrenze sind, entspricht der Modifikator den übergebenen Einschränkungen so genau wie möglich, wobei die übergebenen Einschränkungen eingehalten werden:

Zwei UI-Bäume und ihre entsprechenden Darstellungen in Containern. Im ersten Fall akzeptiert der Größenmodifikator die eingehenden Einschränkungen. Im zweiten Fall passt er sich den zu großen Einschränkungen so genau wie möglich an, was zu Einschränkungen führt, die den Container füllen.
Abbildung 9. Die size-Anpassung, die der übergebenen Einschränkung so genau wie möglich entspricht.

Die Verknüpfung mehrerer size-Modifikatoren funktioniert nicht. Mit dem ersten size-Modifikator werden sowohl die Mindest- als auch die Höchsteinschränkungen auf einen festen Wert festgelegt. Auch wenn der zweite Größenmodifikator eine kleinere oder größere Größe anfordert, muss er dennoch exakt die übergebenen Grenzen einhalten, sodass diese Werte nicht überschrieben werden:

Eine Kette aus zwei Größenmodifikatoren im UI-Baum und deren Darstellung in einem Container, die sich aus dem ersten übergebenen Wert und nicht aus dem zweiten Wert ergibt.
Abbildung 10. Eine Kette aus zwei size-Modifizierern, bei der der zweite übergebene Wert (50dp) den ersten Wert (100dp) nicht überschreibt.

requiredSize-Modifikator

Verwenden Sie den Modifikator requiredSize anstelle von size, wenn der Knoten die eingehenden Einschränkungen überschreiben soll. Der requiredSize-Modifikator ersetzt die eingehenden Einschränkungen und übergibt die von Ihnen angegebene Größe als genaue Grenzen.

Wenn die Größe wieder nach oben in den Baum übergeben wird, wird der untergeordnete Knoten im verfügbaren Bereich zentriert:

Die in einem UI-Baum verkettete Modifikatorgröße für Größe und requiredSize sowie die entsprechende Darstellung in einem Container. Die Einschränkungen des Modifikators „requiredSize“ überschreiben die Einschränkungen des Modifikators „size“.
Abbildung 11. Der requiredSize-Modifikator, der eingehende Einschränkungen aus dem size-Modifikator überschreibt.

width- und height-Modifikatoren

Mit dem Modifizierer size werden sowohl die Breite als auch die Höhe der Einschränkungen angepasst. Mit dem Modifikator width können Sie eine feste Breite festlegen, die Höhe aber offen lassen. Mit dem Modifikator height können Sie auch eine feste Höhe festlegen, die Breite aber offen lassen:

Zwei UI-Bäume, einer mit dem Modifikator „Breite“ und seiner Containerdarstellung und der andere mit dem Modifikator „Höhe“ und seiner Darstellung.
Abbildung 12. Mit dem Modifizierer width wird eine feste Breite und mit dem Modifizierer height eine feste Höhe festgelegt.

sizeIn-Modifikator

Mit dem Modifikator sizeIn können Sie genaue Mindest- und Höchstwerte für Breite und Höhe festlegen. Verwenden Sie den Modifikator sizeIn, wenn Sie die Einschränkungen genau steuern möchten.

Einen UI-Baum mit dem Modifikator sizeIn mit minimaler und maximaler Breite und Höhe sowie dessen Darstellung in einem Container.
Abbildung 13. Den sizeIn-Modifikator, wobei minWidth, maxWidth, minHeight und maxHeight festgelegt sind.

Beispiele

In diesem Abschnitt wird die Ausgabe mehrerer Code-Snippets mit verketteten Modifikatoren gezeigt und erläutert.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

Dieses Snippet erzeugt die folgende Ausgabe:

  • Der Modifikator fillMaxSize ändert die Einschränkungen, um sowohl die minimale Breite als auch die minimale Höhe auf den Maximalwert zu setzen: 300dp in der Breite und 200dp in der Höhe.
  • Auch wenn für den size-Modifikator eine Größe von 50dp verwendet werden soll, müssen die Mindesteinschränkungen für eingehende Nachrichten eingehalten werden. Der Modifikator size gibt also auch die genauen Einschränkungsgrenzen von 300 × 200 aus und ignoriert dabei den im Modifikator size angegebenen Wert.
  • Die Image folgt diesen Grenzen und meldet eine Größe von 300 × 200, die bis zum Stamm des Baums weitergegeben wird.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .wrapContentSize()
        .size(50.dp)
)

Dieses Snippet erzeugt die folgende Ausgabe:

  • Der fillMaxSize-Modifikator passt die Einschränkungen an, um sowohl die Mindestbreite als auch die minimale Höhe auf den Maximalwert zu setzen: 300dp in der Breite und 200dp in der Höhe.
  • Mit dem Modifikator wrapContentSize werden die Mindesteinschränkungen zurückgesetzt. Während fillMaxSize zu festen Einschränkungen führte, setzt wrapContentSize es auf die begrenzten Einschränkungen zurück. Der folgende Knoten kann jetzt wieder den gesamten Bereich einnehmen oder kleiner als der gesamte Bereich sein.
  • Der size-Modifikator legt die Einschränkungen auf die Mindest- und Höchstwerte von 50 fest.
  • Image wird in eine Größe von 50 × 50 aufgelöst und der Modifikator size leitet diese weiter.
  • Der Modifikator wrapContentSize hat eine besondere Eigenschaft. Das untergeordnete Element wird in die Mitte der verfügbaren Mindestgrenzen gesetzt, die ihm übergeben wurden. Die Größe, die an die übergeordneten Elemente gesendet wird, entspricht daher den Mindestgrenzwerten, die übergeben wurden.

Indem Sie nur drei Modifikatoren kombinieren, können Sie eine Größe für die zusammensetzbare Funktion definieren und sie auf das übergeordnete Element zentrieren.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .clip(CircleShape)
        .padding(10.dp)
        .size(100.dp)
)

Dieses Snippet führt zur folgenden Ausgabe:

  • Der clip-Modifikator ändert die Einschränkungen nicht.
    • Der padding-Modifikator senkt die maximalen Beschränkungen.
    • Mit dem Modifikator size werden alle Einschränkungen auf 100dp festgelegt.
    • Die Image entspricht diesen Einschränkungen und hat eine Größe von 100 × 100dp.
    • Der Modifizierer padding fügt allen Größen 10dp hinzu, wodurch die gemeldete Breite und Höhe um 20dp erhöht wird.
    • In der Zeichenphase wirkt der clip-Modifikator auf ein Canvas von 120 × 120dp ein. Es wird also eine Kreismaske dieser Größe erstellt.
    • Der Modifizierer padding rückt den Inhalt dann in allen Größen um 10dp ein, wodurch die Canvas-Größe um 100dp auf 100 verringert wird.
    • Die Image wird in diesem Canvas gezeichnet. Das Bild wird anhand des ursprünglichen Kreises von 120dp zugeschnitten, sodass das Ergebnis nicht rund ist.