DSVGO
Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu.
Server Wartungsarbeiten
...
Diese Variante bietet sich vor allem an, wenn die Layoutgruppe sowieso schon unterhalb einer anderen Gruppe liegt (Beispiel: Mehrere Zeilen Inhalt innerhalb Panels, also horizontale Gruppen unter einer vertikalen). Vielleicht will man auch andere Alignment Optionen nehmen oder Force Expand nutzen. Leider kann man wie gesagt nur auf der kontrollierten Achse Padding erzeugen - auf der anderen geht das nur mit einer der beiden zuvor beschriebenen Methoden.
Für die einfachste Form von Layout platziert man UI Elemente relative zum Canvas oder einander. Jedes GameObject unter einem Canvas erhält ein Rect(angle) Transform an Stelle der normalen Transform Komponente.
[Beispiel]
Ganz oben ist wie gewohnt die Position des Objekts. Darunter befinden sich nun Einstellungen für die Breite und Höhe des Elements - denn jedes Element unter dem Canvas wird als Rechteck dargestellt. Ebenfalls wieder zu finden sind Rotation und Skalierung.
Im normalen Kontext ist man gewöhnt Skalierung zu benutzen, um Objekte größer oder kleiner zu machen. Innerhalb der UI macht es mehr Sinn stattdessen Breite und Höhe anzupassen (Resizing). Das hat vor allem den Grund, das die meisten UI Komponenten nur mit diesen Werten interagieren. Ein weiterer Anwendungsfall sind Sliced Images, wo das Resizing keinen Einfluss auf den Rand des Bildes hat - Skalierung aber schon.
Es bietet sich als Konvention an für statische Größen immer Breite und Höhe zu verwenden, während dynamische Größe über Skalierung geregelt wird (Beispiel: Animationen).
Wenn man ein UI Objekt anwählt sieht man einen Kreis, meist in der Mitte des Rechtecks. Dieser Kreis ist der sog. Pivot Point, das Zentrum des Elements. Seine Position ist im Rect Transform mit relativen Werten zwischen 0 und 1 angegeben. Die Position (0,0) ist dabei links unten im Rechteck.
[Beispeil aus der rect doku]
Alle Transformationen - Verschieben, rotieren, skalieren, resizing - passieren ausgehend vom Pivot bzw. um ihn herum.
Dazu ein paar Beispiele:
Das gelbe Rechteck hat den Standard Pivot von (0.5, 0,5) und das rote den Pivot links unten (0,0). Beide sind haben ihren Anker in der Mitte des Canvas.
Bei Position (0,0,0) befinden sich beide Rechtecke mit ihrem Pivot genau auf dem Anker. Entsprechend ist gelb genau in der Mitte, während von rot die linke untere Ecke in der Mitte ist.
Für das nächste Beispiel habe ich beide Rechtecke in die Bildschirmmitte bewegt und dann um 10 Grad auf der Z-Achse rotiert:
Das gelbe Rechteck rotiert auf der Stelle. Das rote Rechteck hingegen hat sich um seine linke untere Ecke rotiert, weswegen eine Verschiebung zwischen den beiden passiert ist.
Ich bewege die beiden Rechtecke wieder in die Mitte und verdopple die Skalierung auf der X-Achse:
Wenn man den Alpha-Wert des roten Rechtecks auf die Hälfte reduziert, kann man erkennen, dass es sich weiter nach rechts ausgedehnt hat, als das gelbe. Skalierung geschieht vom Pivot weg, deswegen ist das rote Rechteck mit Pivot links in Richtung rechts gewachsen.
Eine Änderung der Breite auf den doppelten Wert verhält sich analog.
Anker sind ein gängiges Layout Konzept. Sie bestimmen zu welchem Punkt innerhalb des Parent-Rechtecks die eigene Position relativ ist – ähnlich wie beim normalen Transform, wo die Position relativ zum Ursprung des Parents ist. Ein Child ist standardmäßig zum Zentrum geankert. Häufige andere Konfigurationen können als Presets gefunden werden, indem man auf das Anchor Preset Symbol links oben im Rect Transform klickt.
Repräsentiert werden Anker durch vier dreieckige Griffe im Scene View. Im Inspector gibt es die Sektion „Anchors“, unter der Min und Max als Ankerpositionen gelistet sind. Min beschreibt dabei die linke untere Ecke bzw. den linken unteren Anker und Max den rechten oberen. Die Ankerpositionen werden als Werte zwischen 0 und 1 angegeben. Solange die beiden Anker am selben Punkt liegen, besitzt das Rechteck eine fixe Breite und Höhe, während es sich relativ zum Parent positioniert.
Zieht man sie auseinander, entsteht auf der entsprechenden Achse eine relative und damit flexible Größe. In diesem Fall kann man die Werte von Min und Max als Prozente interpretieren, also 0 entspricht 0% und 1 entspricht 100%. Wenn die Anker beispielsweise jeweils auf der Ober- bzw. Unterkante des Parent-Rechtecks liegen, nimmt es immer die volle Höhe ein. Wenn der Parent schrumpft, schrumpft auch das gelbe Rechteck und das gleiche gilt auch fürs Wachsen.
Diese Konfiguration entspricht dem Preset "Strech - center". An Stelle einer absoluten Position auf der vertikalen Achse kann man nun ein Padding für "Top" und "Bottom" setzen. Man kann ebenfalls sehen, dass Anchor.Min.Y 0% und Anchor.Max.Y 100% sind - woraus das Stretching in der Höhe resultiert.
Die Werte für Ankerpositionen sind frei wählbar. Man kann damit relative Layouts erstellen- wählt man z.B. folgende Werte:
erhält man dieses gelbe Rechteck:
Aufgeschlüsselt entsteht es so:
Ein weiteres Anwendungsbeispiel findet sich im Kapitel "Die Safe Zone".
Ein Layoutelement ist grundsätzlich erst einmal jedes GameObject mit einem Rect Transform. Es weiß im Grunde genommen, welche Size es haben sollte, setzt diese aber nicht selbst - lediglich die Information wird an die sog. Layout Controller weitergegeben, damit diese dem Element eine Size zuweisen können.
Pro Dimension (Width, Height) verfügt jedes Layoutelement über drei Sizes:
Sehen kann man diese ganz unten im Inspector, unter "Layout Properties". Manchmal ist diese Ansicht in einem Dropdown versteckt - wenn beispielsweise ein Image auf dem GameObject liegt, wird ein Preview vom Sprite angezeigt.
[Beispiel]
Wenn ein Layoutcontroller beginnt die Size zuzuweisen, betrachtet er nacheinander von jedem Element diese drei Sizes. Zuerst erhält jedes Element seine Minimum Size. Wenn danach noch Raum übrig ist, wird damit begonnen Elemente in Richtung ihrer Preferred Size wachsen zu lassen. Die Elemente wachsen so lang weiter, bis sie ihre Preferred Size erreicht haben oder kein weiterer Raum mehr zur Verfügung steht. Sollte danach immer noch Raum zur Verfügung stehen, wachsen alle Elemente mit Flexible Size weiter, bis auch dieser Raum aufgebraucht ist.
Die Standardwerte für die Sizes sind 0. Während Minimum und Preferred Size tatsächlich Größenangaben sind, ist Flexible Size ein relativer Wert zwischen 0 und 1 - bedeutet also das Element nimmt gar keinen (Wert 0) oder den ganzen (Wert 1) verfügbaren Restraum ein. Sollten mehrere Elemente die gleiche Flexible Size haben, erhalten sie gleich viel Raum.
Anmerkung: Wenn mehrere Elemente eine Flexible Size haben und diese Sizes aufsummiert mehr als 1 ergeben wird die ganze Berechnung ein wenig unintuitiv. Nehmen wir zwei Layoutelemente A und B an. A hat eine Flexible Size von 1 und B eine von 4. Es steht ein Restraum von 10 Units zur Verfügung. Die zugeteilte Size ist jetzt 10 x Flexible Size / Summe aller Flexible Sizes - bedeutet also A erhält 10 x 1 / 5 = 2 units und B erhält 8 units. Ich würde daher vorschlagen darauf zu achten, dass Flexible Sizes entweder gleich groß sind oder sich zu 1 aufsummieren.
Es gibt bestimmte (Layout-) Komponenten, die die Standardwerte der Sizes überschreiben. Einfache Beispiele dafür sind "Layout Element", "Image" und "Text". Image und Text werden die Sizes immer so setzen, dass das Element den entsprechenden Inhalt fassen kann. Wenn ein Sprite also 50 units Breite hat, setzt die Image-Komponente seine Preferred Size entsprechend.
Laylout Element bietet die Möglichkeit alle Werte auf dem GameObject explizit zu überschreiben.
[Beispiel]
Wann immer man Elemente in seinem Layout hat, deren Werte sich nicht automatisch ergeben oder denen man eine andere Größe als die automatische zuweisen will, benutzt man diese Komponente. Ein Anwendungsfall von mir sind "Spacer"-Objekte, welche ich für flexiblen Leerraum bzw. flexible Abstände nutze. Solche Objekte sind nichts anderes als empty GameObjects mit einem Layout Element drauf, damit sie im Layout Platz einnehmen.
[Beispiel]
Neben den Sizes bietet das Layout Element noch zwei weitere Optionen:
Ignore Layout ist ein Toggle und kommuniziert an Layoutcontroller auf dem Parent, dass dieses Objekt nicht teil des Layouts ist. Das ist nützlich, um Objekte innerhalb einer Layoutgruppe oder in Relation zu dieser zu platzieren, ohne das Layout zu beeinflussen.
[Beispiel]
Layout Priority legt die Priorität dieser Layout-Komponente gegenüber anderen fest. Das bedeutet, dass immer die Sizes von dem Element mit der höchsten Priorität an Layoutcontroller kommuniziert werden. Eine Layoutgruppe hat beispielsweise die Priorität 0 (steht als Property im Source Code). Wenn man jetzt auf dem gleichen GameObject ein Layout Element hinzufügt, dass standardmäßig mit Priorität 1 startet, überschreibt dieses die Sizes der Gruppe.
[Beispiel]
Setzt man die Priorität des Layout Elements auf -1, ist die Gruppe wieder priorisiert.
[Beispiel]
Sind mehrere Komponenten mit der gleichen Priorität aktiv, wird immer der höchste Wert von allen gewählt.
Jetzt mal ein paar Beispiele.
Hierarchie:
Zunächst erhalten Element A und B ihre Minimum Size von 10 bzw. 30. Danach ist noch Raum von 60 units übrig. Element B verfügt über keine weiteren Size Einstellungen und ist entsprechend fertig. Element A hat eine Preferred Size von 50 und möchte damit noch um weitere 40 Units wachsen. Da dieser Raum noch verfügbar ist, kann Element A seine Preferred Size erreichen und ist nun 50 units groß. Es bleiben 20 units als Leerraum im Layout zurück, da diese nicht beansprucht wurden.
Was ist aber nun, wenn beide Elemente eine Flexible Size haben?
Hierarchie:
Das verhalten bleibt bis zum Zuweisen der Flexible Size zunächst einmal gleich. Danach werden die Flexible Size Werte betrachtet. Diese sind gleich groß, also erhalten beide Elemente die Hälfte der verbleidenden 20 units. Element A erreicht so eine Größe von 60 units. Element B wächst auf 40 Units heran.
Nehmen wir als nächstes an, dass wir die Flexible Size ungleich verteilen wollen:
Hierarchie:
In diesem Fall erhält A genau ein Viertel, also 5, zusätzliche units und B die restlichen drei Viertel, entsprechend 15 units.
Im letzten Beispiel reicht die Size der Gruppe nicht aus, um beide Elemente auf ihre gesamte Preferred Size anwachsen zu lassen:
Hierarchie:
In diesem Fall wachsen beide Elemente gleichmäßig, bis der Raum vollständig aufgebraucht ist. Element A endet hier bei in etwa 44 units. Element B bei 56. Beide Elemente sind ähnlich weit von ihrer Preferred Size entfernt - Element B ist näher dran, weil die Differenz zwischen Minimum Size und Preferred Size bei ihm geringer ausfiel.
Layout Controller kontrollieren die Size und/oder Position von einem oder mehreren Layoutelement(en). Es gibt zwei Sorten von Layout Controllern:
Fitter kontrollieren immer ihr eigenes Layout Element, also das Objekt, auf dem sie platziert sind.
Der Aspect Ratio Fitter verändert das Element so, dass es eine bestimmte Aspect Ratio einhält. Dafür orientiert er sich an den Maßen seines Parents. Für diese Orientierung gibt es verschiedene Modi:
Die Breite des Parents wird für die Bestimmung der Höhe genutzt. [Beispiel]
Die Höhe des Parents wird für die Bestimmung der Breite genutzt. [Beispiel]
In diesem Modus wächst das Element gleichmäßig auf beiden Achsen unter Einhaltung der Aspect Ratio. Sobald eine Achse mit der des Parents gleich zieht wird gestoppt. Je nach dem, wie gut die gewählte Aspect Ratio zu der des Parents passt, kann es sein, dass Element diesen nicht komplett ausfüllt. [Beispiele]
Ähnliches Verhalten wie "Fit in Parent". Allerdings wird hier gewachsen, bis beide Achsen gleichziehen. Das führt dazu, dass das Element den Parent komplett ausfüllt und gegebenenfalls auf einer Achse über steht.
[Beispiele]
Ich habe den Aspect Ratio Fitter z.B. für einen Loadscreen genutzt. Dazu nutze ich den Modus Envelope Parent und trage die Aspect Ratio der Grafik in den Fitter ein.
[Beispiel]
Dieser Loadscreen wird immer den ganzen Bildschirm ausfüllen - allerdings ist die Grafik gegebenenfalls herangezoomed.
Mit den Control Modi für Width/Height kann man ein ähnliches Verhalten wie die Funktion "Preserve Aspect" auf der Image-Komponente erhalten. Der wichtige Unterschied dabei ist, dass das Bild auch tatsächlich so groß wird, wie es die Aspect-Ratio vorgibt und nicht nur so aussieht. Das erlaubt einem dann korrekte Verankerung am Image.
[Beispiel]
Größtes Problem des Aspect Ratio Fitters ist, dass man ihn nur nutzen kann, wenn das Element nicht von einer Layoutgruppe gesteuert wird. Ein Problem was sich auch bei der nächsten Komponente fortsetzt.
Der Content Size Fitter setzt die Maße des Elements basierend auf einem Layout Component auf dem gleichen Objekt. Das können beispielsweise Layoutgruppen, Images oder Text sein. Er verfügt über folgende Optionen, die jeweils auf die horizontale oder vertikale Achse angewendet werden können:
Der Content Size Fitter hat keinen Effekt auf diese Achse.
Das Element wird vom Content Size Fitter immer auf seine minimale Größe gesetzt.
Das Element wird immer auf die Preffered Size gesetzt.
Der Catch an dem Content Size Fitter ist für mich, dass er nicht flexibel funktioniert, sondern ausschließlich fix ist. Man könnte annehmen, dass die letzte Option ein flexibles Wachsen wie bei den anderen Elementen von Auto Layout bewirkt - das ist aber nicht der Fall. Es wird immer exakt auf die Preffered Size gesetzt.
Für mich leistet der Content Size Fitter seine Arbeit vor allem auf Root Elementen von Panels, um automatisch die richtige Größe einzustellen. Eine weitere gute Anwendung ist in Kombination mit Text, wo der Content Size Fitter den Text Container wachsen lässt um den Text bei gleicher Schriftgröße einzufassen. Er ist ebenfalls sehr nützlich für die Gridlayoutgruppe.
Gruppen kontrollieren Größe und Position ihrer Childs.
Jede Layoutgruppe hat folgende Optionen:
Man kann auch negative Werte nutzen, was die Size der Gruppe verringert. Damit sich die Childs überlappen, fügt man negatives Spacing hinzu. Bei negativen Padding ragen sie dann aus der Gruppe heraus.
Diese Einstellung beeinflusst vor allem, in bzw. aus welcher Richtung sich die Gruppe füllt. Mit Alignment "Center …" bleiben die kontrollierten Elemente beispielsweise zentriert.
Eine Layoutgruppe fungiert selbst als Layoutelement. Ihre Werte entsprechen der Summe der Werte ihrer Childs. Sind in einer Gruppe beispielsweise drei Elemente mit Minimum Width 50, so hat die Gruppe eine Minimum Width von 150.
Padding bzw. Spacing werden ebenfalls noch dazugerechnet. Hat die Gruppe zusätzlich noch ein Spacing von 30, ist ihre Minimum Width 210 (150 von den Childs plus zwei Spacings von 30 zwischen den drei Childs).
Die berechnete Größe wird dann auch an Layout Controller auf dem Parent der Gruppe oder an Fitter auf dem gleichen Objekt weitergegeben. Entsprechend kann man Layoutgruppen auch schachteln.
Es ist wichtig, dass eine Gruppe groß genug ist, um all ihre Childs einzufassen. Sollte eine Achse zu klein sein, beginnen Childs aus der Gruppe herauszuragen. Am einfachsten kann man das über Fitter Komponenten wie den Content Size Fitter verhindern, welche die Layout-Informationen der Gruppe nutzen, um ihre Maße entsprechend ihrer Childs anzupassen.
Horizontale bzw. vertikale Gruppen platzieren ihre Childs nebeneinander auf der entsprechenden Achse.
Bei diesen Gruppen gibt es noch weitere Optionen:
Ist vor allem nützlich, wenn die Sortierung von der Reihenfolge abweicht - da in der UI immer das unterste Objekt vorne angezeigt wird und sich die Gruppe immer von oben nach unten füllt. Möchte man das vorn angezeigte Objekt im Layout an erster Stelle haben, nutzt man "Reverse Arrangement".
Basierend auf der eigenen Größe probiert die Gruppe ihren Childs die entsprechende Menge an Minimum-/Preffered-/Flexible Size zuzuteilen. Wie genau diese Verteilung ausfällt wird von den drei Kontroll-Optionen beeinflusst:
Wenn ja - wird den Childs auf der entsprechenden Achse Minimum-/Preffered-/Flexible Size zugeteilt. Nehmen wir einmal folgendes Beispiel an: Unsere Layoutgruppe hat eine feste Größe von 300px, ohne Spacing und Padding. Unter ihr befinden sich drei Elemente mit Min Size 50 und Preferred Size 200. Zunächst wachsen alle Elemente auf ihre Minimum Size von 50, womit 150px der Gruppe belegt sind. Da alle Elementen eigentlich 200px groß sein wollen, kann jedes von ihnen noch wachsen. Die restlichen 150px werden also der entsprechenden Priorität nach auf die Elemente verteilt. Somit sind schlussendlich alle Elemente 100px groß.
Wenn nein - wird nur die Position der Childs durch die Layoutgruppe gesetzt.
So oder so gilt: Sollte die Gruppe nicht groß genug sein, um ihre Childs zu fassen, beginnen diese aus ihr herauszuragen.
Beispiel: Ein Element hat Min Size 100, aber einen Scale von 0.5 auf der entsprechenden Achse.
Wenn ja - Die Layoutgruppe behandelt das Element mit seiner echten Größe von 50.
Wenn nein - Das Element wird so behandelt, als hätte es trotz Scaling seine volle Größe von 100.
Bei dieser Option dreht es sich darum, was mit freiem Platz geschehen soll, der von keinem Element beansprucht wird.
Wenn nein - Der freie Platz bleibt leer.
Wenn ja - Die Elemente werden so verändert, dass sie den Raum voll ausfüllen.
Wenn auf der entsprechenden Achse auch die Size kontrolliert wird wachsen alle Elemente, bis die Gruppe ausgefüllt ist.
Falls die Size nicht kontrolliert wird, entsteht Spacing zwischen den Elementen.
Eine Gridlayoutgruppe platziert Childs auf einem Grid. Sie verfügt über folgende zusätzliche Optionen:
Diese Layoutgruppe ignoriert Size-Einstellungen der enthaltenen Elemente. Stattdessen wird jedem Child die fixe Zellengröße zugeteilt.
Die Starteinstellungen sind maßgeblich dafür, wie sich das Grid füllt. Start Corner bestimmt den Ursprung. Start Axis kann horizontal oder vertikal sein und bestimmt die Tendenz zuerst Reihen bzw. Spalten zu füllen, bevor eine neue Spalte bzw. Reihe angefangen wird. Wann eine Zeile bzw. Spalte voll ist, wird durch die Breite bzw. Höhe des Gruppen Elements bestimmt.
Es gibt drei Einstellungen für Constraint: Flexible, Fixed Row- und Fixed Column Count. Flexibel kann man als eine Art ausgeglichene Einstellung verstehen. Reihen und Spalten werden so zugeordnet, dass die Childs in die Gruppe passen. Dabei wird versucht eine ungefähr gleiche Anzahl an Reihen und Spalten zu erhalten.
Allgemein kann es viele mögliche Kombinationen von der Anzahl an Reihen und Spalten geben, welche die Zellen in die Layoutgruppe einfassen. Mit Hilfe von Start Axis und den Row- bzw. Column Count Constrains wird beeinflusst, welche Kombination ausgewählt wird. Das ist vor allem wichtig, wenn man in Kombination mit anderen Auto Layout-Komponenten wie z.B. dem Content Size Fitter arbeitet.
Zur Erinnerung: Auto Layout berechnet Höhe und Breite unabhängig von einander, aber innerhalb eines Grids hängt die Anzahl an Zeilen mit der Anzahl an Spalten zusammen und umgekehrt. Um also korrekt flexible Grids zu erstellen bieten sich folgende Kombinationen an:
In dieser Konfiguration wird das Grid horizontal wachsen, wenn mehr Elemente hinzugefügt werden. Vertical fit auf dem Content Size Fitter sollte ebenfalls auf Preffered Size gesetzt sein, da man sich ansonsten selbst um die Zuweisung einer korrekten Höhe kümmern muss.
Dieses Grid wird vertikal wachsen, wenn mehr Elemente hinzugefügt werden. Erneut: Horizontal fit auf dem Content Size Fitter sollte ebenfalls auf Preffered Size gesetzt sein, da man sich ansonsten selbst um die Zuweisung einer korrekten Breite kümmern müsste.
Man kann ebenfalls auf beiden Achsen flexibel wachsen, bestimmt durch Start Axis. Allerdings verliert man die Kontrolle über die Anzahl an Zeilen und Spalten, welche ungefähr gleich verteilt werden.
Der vielleicht größte Nachteil der Gridlayoutgruppe für die Mobile Plattform ist die fixe Größe der Zellen. Es kann keine unterschiedlich breiten oder hohen Zellen geben. Natürlich lässt sich das Ganze trotzdem auf unterschiedliche Wege erreichen:
Anstatt die Gridzellen direkt mit Inhalt zu füllen können sie auch als Parent für Elemente dienen, die dann frei in der Wahl ihrer Größe sind bzw. ihre Größe immer noch abhängig von der Zellengröße machen können. Beispielsweise kann innerhalb einer Gridzelle auch eine Layoutgruppe geschachtelt sein.
[Beispiel]
Im weitesten Sinn ist die Gridlayoutgruppe nur eine praktische Hilfe für Grids mit einer dynamischen Anzahl an Elementen. Ist die Anzahl an Elementen jedoch statisch bzw. zur Designzeit bereits bekannt, so kann man ein Grid ebenfalls aus verschachtelten Layoutgruppen bauen. Beispielsweise eine horizontale Layoutgruppe als einzelne Zeile, unter der dann vertikale Gruppen als Spalten platziert werden.
[Beispiel]
Die fixe Größe der Zellen kann ebenfalls nicht von Auto Layout, also den Sizes, beeinflusst werden. Sie ist immer gleich, was dazu führen kann, dass Gridlayouts aus ihrem Parent oder dem Bildschirm ragen. Aufgrund dessen würde ich erneut das Schachteln der anderen Layoutgruppen bevorzugen, da man sich ansonsten mit eigenem Code zum Setzen der Zellengröße oder einer eigenen Gridlayoutgruppe behelfen muss.
...