Einschränkungen und Modifikatorreihenfolge

In „Compose“ können Sie mehrere Modifikatoren verketten, um das Aussehen einer zusammensetzbaren Funktion zu ändern. Diese Modifikatorketten können die constraints beeinflussen, die an zusammensetzbare Funktionen übergeben werden, mit denen Breiten- und Höhengrenzen definiert werden.

Auf dieser Seite wird beschrieben, wie sich verkettete Modifikatoren auf Einschränkungen auswirken und somit auf die Messung und Platzierung von zusammensetzbaren Funktionen.

Modifizierer in der Baumstruktur der Benutzeroberfläche

Damit Sie verstehen, wie sich Modifikatoren gegenseitig beeinflussen, ist es hilfreich, zu visualisieren, wie sie im UI-Baum angezeigt werden, der während der Zusammensetzungsphase generiert wird. Weitere Informationen finden Sie im Abschnitt Zusammensetzung.

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

Code für zusammensetzbare Funktionen und Modifikatoren sowie deren visuelle Darstellung als UI-Baum.
Abbildung 1: Modifikatoren, die Layoutknoten in der UI-Baumstruktur zusammenfassen.

Wenn Sie einer zusammensetzbaren Funktion mehrere Modifikatoren hinzufügen, entsteht eine Kette von Modifikatoren. Wenn Sie mehrere Modifikatoren verketten, umfasst jeder Modifikatorknoten den Rest der Kette und den darin enthaltenen Layoutknoten. 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 jeder Modifikatorknoten wird ebenfalls besucht. Auf diese Weise können mit einem Modifikator die Größenanforderungen und die Position des umschlossenen Modifikators oder Layoutknotens geändert werden.

Wie in Abbildung 2 gezeigt, besteht die Implementierung der zusammensetzbaren Funktionen Image und Text selbst aus einer Kette von Modifikatoren, die einen einzelnen Layoutknoten umschließen. Die Implementierungen von Row und Column sind einfach Layoutknoten, die das Layout der untergeordneten Elemente beschreiben.

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

Zusammenfassung:

  • Modifikatoren umschließen einen einzelnen Modifikator oder Layoutknoten.
  • Layoutknoten können mehrere untergeordnete Knoten anlegen.

In den folgenden Abschnitten wird beschrieben, wie Sie dieses mentale Modell nutzen können, um die Modifiziererverkettung zu verstehen und die Größe von zusammensetzbaren Funktionen zu beeinflussen.

Einschränkungen in der Layoutphase

Die Layoutphase folgt einem dreistufigen Algorithmus, um die Breite, Höhe und x- und y-Koordinaten jedes Layoutknotens zu ermitteln:

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

Constraints hilft dabei, 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 sich der Knoten über seine Größe entscheidet, muss seine gemessene Größe in diesen Größenbereich fallen.

Arten von Einschränkungen

Folgende Einschränkungen sind möglich:

  • Begrenzt: Der Knoten hat eine maximale und minimale Breite und Höhe.
Begrenzte Einschränkungen unterschiedlicher Größen innerhalb eines Containers.
Abbildung 3. Begrenzte Einschränkungen.
  • Unbegrenzt: Der Knoten ist auf keine Größe beschränkt. Die maximalen Breiten- und Höhengrenzen sind auf unendlich festgelegt.
Unbegrenzte Einschränkungen, bei denen die Breite und Höhe auf unendlich festgelegt sind. Die Einschränkungen gehen über den Container hinaus.
Abbildung 4. Unbegrenzte Einschränkungen.
  • Genau passend: Der Knoten wird aufgefordert, einer genauen Größenanforderung zu folgen. Die Mindest- und Höchstgrenzen werden auf denselben Wert festgelegt.
Genaue Beschränkungen, die einer genauen Größenanforderung für den Container entsprechen.
Abbildung 5. Exakte 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 bereitstellen.
Zwei Container, die Kombinationen aus begrenzten und unbegrenzten Einschränkungen sowie exakte Breiten und Höhen anzeigen.
Abbildung 6. Kombinationen aus begrenzten und unbegrenzten Einschränkungen sowie exakten Breiten und Höhen.

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

Weitergabe von Einschränkungen von übergeordnetem an untergeordnetes Element

Während des ersten Schritts des Algorithmus, der unter Einschränkungen in der Layoutphase beschrieben wird, werden Einschränkungen in der UI-Struktur von den übergeordneten auf untergeordnete Elemente übergeben.

Wenn ein übergeordneter Knoten seine untergeordneten Knoten misst, stellt er diese Einschränkungen für jeden untergeordneten Knoten bereit, um ihm mitzuteilen, wie groß oder klein sie sein dürfen. Wenn er dann seine eigene Größe festlegt, hält er auch die Einschränkungen ein, die von seinen eigenen übergeordneten Elementen übergeben wurden.

Auf übergeordneter Ebene funktioniert der Algorithmus so:

  1. Um die Größe zu bestimmen, die er tatsächlich belegen möchte, misst der Stammknoten im UI-Baum seine untergeordneten Elemente und leitet diese Einschränkungen an sein erstes untergeordnetes Element weiter.
  2. Wenn das untergeordnete Element ein Modifizierer 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, der sich auf die Messung auswirkt, wird erreicht. Die Größe der Einschränkungen wird dann entsprechend angepasst.
  3. Sobald ein Knoten erreicht wurde, der keine untergeordneten Elemente hat (der als "Blattknoten" bezeichnet wird), bestimmt er seine Größe anhand der übergebenen Einschränkungen und gibt diese aufgelöste Größe an den übergeordneten Knoten zurück.
  4. Das übergeordnete Element passt seine Einschränkungen basierend auf den Messungen dieses untergeordneten Elements an und ruft sein nächstes untergeordnetes Element mit diesen angepassten Einschränkungen auf.
  5. Nachdem alle untergeordneten Elemente eines übergeordneten Knotens gemessen wurden, entscheidet der übergeordnete Knoten seine eigene Größe und kommuniziert dies an seinen eigenen übergeordneten Knoten.
  6. Auf diese Weise wird der gesamte Baum tiefgehend durchlaufen. Schließlich haben alle Knoten ihre Größe festgelegt und der Schritt der Messung ist abgeschlossen.

Ein ausführliches Beispiel finden Sie im Video zu Einschränkungen und Modifikatorreihenfolge.

Modifizierer, die sich auf Einschränkungen auswirken

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

size Modifikator

Der size-Modifikator gibt die bevorzugte Größe des Inhalts an.

Die folgende UI-Struktur sollte beispielsweise in einem Container mit 300dp von 200dp gerendert werden. Die Einschränkungen sind begrenzt und lassen Breiten zwischen 100dp und 300dp sowie Höhen zwischen 100dp und 200dp zu:

Ein Teil einer UI-Baumstruktur mit dem Größenmodifikator, der einen Layoutknoten umschließt, und der Darstellung der begrenzten Einschränkungen, die durch den Größenmodifikator in einem Container festgelegt werden.
Abbildung 7: Begrenzte Einschränkungen in der UI-Baumstruktur und deren Darstellung in einem Container.

Der size-Modifikator passt eingehende Einschränkungen so an, dass sie dem übergebenen Wert entsprechen. In diesem Beispiel lautet der Wert 150dp:

Wie in Abbildung 7, außer dass der Größenmodifikator die eingehenden Einschränkungen so anpasst, dass sie dem übergebenen Wert entsprechen.
Abbildung 8. Der size-Modifikator passt Einschränkungen in 150dp an.

Wenn 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 gleichzeitig die übergebenen Einschränkungen eingehalten werden:

Zwei UI-Baum und ihre entsprechenden Darstellungen in Containern. Im ersten Beispiel akzeptiert der Größenmodifikator die zugehörigen Einschränkungen. In der zweiten passt sich der Größenmodifikator so genau wie möglich an die zu großen Einschränkungen an, was zu Einschränkungen führt, die den Container ausfüllen.
Abbildung 9. Den size-Modifikator, der so genau wie möglich an die übergebene Einschränkung hält.

Beachte, dass das Verketten mehrerer size-Modifikatoren nicht funktioniert. Der erste size-Modifizierer legt sowohl die minimale als auch die maximale Einschränkung auf einen festen Wert fest. Auch wenn der zweite Größenmodifikator eine kleinere oder größere Größe anfordert, muss er genau die übergebenen Grenzen einhalten, sodass diese Werte nicht überschrieben werden:

Eine Kette aus zwei Größenmodifikatoren in der UI-Baumstruktur und ihrer Darstellung in einem Container, die das Ergebnis des ersten übergebenen Werts und nicht das Ergebnis des zweiten Werts ist.
Abbildung 10. Eine Kette von zwei size-Modifikatoren, bei denen der zweite 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 exakte Grenzen.

Wenn die Größe wieder an den Baum übergeben wird, wird der untergeordnete Knoten in der Mitte des verfügbaren Platzes zentriert:

Der Modifikator „size“ und „requiredSize“ sind in einer UI-Struktur sowie die entsprechende Darstellung in einem Container verkettet. Die Einschränkungen des Größenmodifikators überschreiben die Einschränkungen des Größenmodifikators.
Abbildung 11. Der requiredSize-Modifikator, der die eingehenden Einschränkungen vom size-Modifikator überschreibt

width und height Modifikatoren

Der size-Modifikator passt sowohl die Breite als auch die Höhe der Einschränkungen an. Mit dem Modifikator width können Sie eine feste Breite festlegen, aber keine Höhe festlegen. In ähnlicher Weise können Sie mit dem Modifikator height eine feste Höhe festlegen, aber keine Breite festlegen:

Zwei UI-Bäume, einer mit dem Breitenmodifikator und seiner Containerdarstellung, der andere mit dem Höhenmodifikator und dessen Darstellung.
Abbildung 12. Der width-Modifikator und der height-Modifikator legen jeweils eine feste Breite bzw. Höhe fest.

sizeIn Modifikator

Mit dem sizeIn-Modifikator können Sie exakte minimale und maximale Breite und Höhe festlegen. Verwenden Sie den sizeIn-Modifikator, wenn Sie eine detaillierte Kontrolle über die Einschränkungen benötigen.

Ein UI-Baum, in dem der Modifikator „sizeIn“ mit minimalen und maximalen Breiten und Höhen festgelegt ist und der Darstellung in einem Container entspricht.
Abbildung 13. Der sizeIn-Modifikator mit festgelegten minWidth, maxWidth, minHeight und maxHeight

Beispiele

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

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

Dieses Snippet erzeugt folgende Ausgabe:

  • Der Modifikator fillMaxSize ändert die Einschränkungen, um sowohl die Mindestbreite als auch die Mindesthöhe auf den Maximalwert festzulegen – 300dp in der Breite und 200dp in der Höhe.
  • Obwohl der size-Modifikator eine Größe von 50dp verwenden möchte, muss er dennoch die eingehenden Mindesteinschränkungen einhalten. Der size-Modifikator gibt also auch die genauen Einschränkungsgrenzen von 300 nach 200 aus und ignoriert praktisch den Wert, der im size-Modifikator angegeben ist.
  • Das Image folgt diesen Grenzen und meldet eine Größe von 300 nach 200, die bis zur Baumstruktur übergeben wird.

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

Dieses Snippet erzeugt folgende Ausgabe:

  • Der fillMaxSize-Modifikator passt die Einschränkungen an, um sowohl die Mindestbreite als auch die Mindesthöhe auf den Maximalwert – 300dp in der Breite und 200dp in der Höhe – festzulegen.
  • Der wrapContentSize-Modifikator setzt die Mindesteinschränkungen zurück. Während fillMaxSize zu festen Einschränkungen geführt hat, setzt wrapContentSize den Parameter auf begrenzte Einschränkungen zurück. Der folgende Knoten kann jetzt den gesamten Bereich wieder einnehmen oder kleiner als der gesamte Bereich sein.
  • Der size-Modifikator legt die Einschränkungen auf die Mindest- und Höchstgrenzen von 50 fest.
  • Der Image wird in eine Größe von 50 nach 50 aufgelöst und der size-Modifikator leitet diese weiter.
  • Der wrapContentSize-Modifikator hat eine spezielle Eigenschaft. Dabei wird das untergeordnete Element in die Mitte der verfügbaren Mindestgrenzen gesetzt, die an das untergeordnete Element übergeben wurden. Die Größe, die den übergeordneten Elementen mitgeteilt wird, entspricht somit den Mindestgrenzen, die ihr übergeben wurden.

Wenn Sie nur drei Modifikatoren kombinieren, können Sie eine Größe für die zusammensetzbare Funktion definieren und in ihrer übergeordneten Funktion zentrieren.

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

Dieses Snippet erzeugt folgende Ausgabe:

  • Der clip-Modifikator ändert die Einschränkungen nicht.
    • Der padding-Modifikator senkt die maximalen Beschränkungen.
    • Der size-Modifikator setzt alle Einschränkungen auf 100dp.
    • Der Image erfüllt diese Einschränkungen und meldet eine Größe von 100 mal 100dp.
    • Der padding-Modifikator fügt bei allen Größen 10dp hinzu, sodass die gemeldete Breite und Höhe um 20dp erhöht wird.
    • In der Zeichenphase wird der clip-Modifikator jetzt auf einer Canvas mit 120 nach 120dp agiert. Daher wird eine Kreismaske dieser Größe erstellt.
    • Der padding-Modifikator fügt dann seinen Inhalt bei allen Größen um 10dp ein, sodass die Canvasgröße auf 100 um 100dp reduziert wird.
    • Image wird auf diesem Canvas gezeichnet. Das Bild wird basierend auf dem ursprünglichen Kreis von 120dp zugeschnitten. Die Ausgabe ist also kein rundes Ergebnis.