Zusammenfassung für Kapitel 26: Benutzerdefinierte Layouts

Beispiel herunterladen Das Beispiel herunterladen

Hinweis

Dieses Buch wurde im Frühjahr 2016 veröffentlicht und seitdem nicht aktualisiert. Wenngleich ein großer Teil des Buchs weiterhin relevante Informationen liefert, sind einige Abschnitte veraltet, und einige Themen sind nicht mehr korrekt oder vollständig.

Xamarin.Forms umfasst eine Reihe von Klassen, die von Layout<View> abgeleitet sind:

  • StackLayout,
  • Grid,
  • AbsoluteLayout und
  • RelativeLayout.

In diesem Kapitel wird beschrieben, wie Sie eigene Klassen erstellen, die von Layout<View> abgeleitet werden.

Das Layout im Überblick

Es gibt kein zentralisiertes System zur Verarbeitung des Xamarin.Forms-Layouts. Jedes Element bestimmt die eigene Größe selbst und ermittelt, wie es innerhalb eines bestimmten Bereichs gerendert wird.

Über- und untergeordnete Elemente

Jedes Element, das über untergeordnete Elemente verfügt, ist für die Positionierung dieser untergeordneten Elemente verantwortlich. Die Größe der untergeordneten Elemente wird dabei vom übergeordneten Element basierend auf der verfügbaren Größe und der vom untergeordneten Element angestrebten Größe bestimmt.

Festlegung der Größe und Positionierung

Für das Layout wird im oberen Bereich der visuellen Struktur mit der Seite begonnen, auf die alle Branches folgen. Die wichtigste öffentliche Methode im Layout wird Layout durch VisualElementdefiniert. Jedes übergeordnete Element ruft für jedes seiner untergeordneten Elemente Layout auf, um die Größe des Elements festzulegen und seine Position zu bestimmen (relativ zum übergeordneten Element). Zu diesem Zweck wird ein Rectangle-Wert angegeben. Diese Aufrufe von Layout werden innerhalb der visuellen Struktur propagiert.

Damit ein Element auf dem Bildschirm angezeigt wird, muss Layout aufgerufen werden. Dadurch werden die folgenden schreibgeschützten Eigenschaften festgelegt. Diese Eigenschaften stimmen mit dem Rectangle-Wert überein, der an die Methode übergeben wird:

  • Bounds vom Typ Rectangle
  • X vom Typ double
  • Y vom Typ double
  • Width vom Typ double
  • Height vom Typ double

Vor dem Layout Aufruf Height und Width haben Mockwerte von –1.

Durch den Aufruf von Layout wird zudem der Aufruf der folgenden geschützten Methoden ausgelöst:

Schließlich wird das folgende Ereignis ausgelöst:

Die Methode OnSizeAllocated wird durch Page und Layout überschrieben, den einzigen beiden Klassen in Xamarin.Forms, die über untergeordnete Elemente verfügen können. Die außer Kraft gesetzten Methodenaufrufe

LayoutChildren ruft dann für jedes untergeordnete Element des Elements Layout auf. Wenn mindestens ein untergeordnetes Element über eine neue Bounds-Einstellung verfügt, wird das folgende Ereignis ausgelöst:

Constraints und Größenanforderungen

Damit LayoutChildren einen intelligenten Aufruf von Layout für alle seine untergeordneten Elemente durchführen kann, muss eine bevorzugte oder gewünschte Größe der untergeordneten Elemente bekannt sein. Aus diesem Grund wird den Aufrufen von Layout für die einzelnen untergeordneten Element in der Regel folgender Aufruf vorangestellt:

Nach der Veröffentlichung dieses Buchs wurde die Methode GetSizeRequest durch folgende Methode ersetzt:

Die Methode Measure umfasst die Margin-Eigenschaft sowie ein Argument vom Typ MeasureFlag, das über zwei Member verfügt:

Bei vielen Elementen ruft GetSizeRequest oder Measure die native Größe des Elements von seinem Renderer ab. Beide Methoden verfügen über Constraints für Breite und Höhe. Label verwendet z.B. die Breitenbeschränkung, um zu ermitteln, wie mehrere Textzeilen umbrochen werden.

Sowohl GetSizeRequest als auch Measure geben einen Wert vom Typ SizeRequestzurück, der über zwei Eigenschaften verfügt:

Diese beiden Werte sind häufig identisch, und der Minimum-Wert kann üblicherweise ignoriert werden.

VisualElement definiert zudem eine geschützte Methode, die GetSizeRequest ähnelt und von GetSizeRequest aufgerufen wird:

Diese Methode ist inzwischen veraltet und wurde wie folgt ersetzt:

Jede Klasse, die von Layout oder Layout<T> abgeleitet wird, muss OnSizeRequest oder OnMeasure außer Kraft setzen. An dieser Stelle bestimmt eine Layoutklasse ihre eigene Größe, die im Allgemeinen auf der Größe ihrer untergeordneten Elemente basiert, die sie durch einen Aufruf von GetSizeRequest oder Measure für die untergeordneten Elemente erhält. Vor und nach dem Aufruf von OnSizeRequest oder OnMeasure nimmt GetSizeRequest oder Measure basierend auf den folgenden Eigenschaften Anpassungen vor:

  • WidthRequest vom Typ double, wirkt sich auf die Request-Eigenschaft von SizeRequest aus
  • HeightRequest vom Typ double, wirkt sich auf die Request-Eigenschaft von SizeRequest aus
  • MinimumWidthRequest vom Typ double, wirkt sich auf die Minimum-Eigenschaft von SizeRequest aus
  • MinimumHeightRequest vom Typ double, wirkt sich auf die Minimum-Eigenschaft von SizeRequest aus

Unbegrenzte Constraints

Die an GetSizeRequest (oder Measure) und OnSizeRequest (oder OnMeasure) übergebenen Argumente können unbegrenzt sein (d.h. Werte von Double.PositiveInfinity). Der von diesen Methoden zurückgegebene SizeRequest-Wert kann jedoch keine unbegrenzten Dimensionen enthalten.

Unbegrenzte Constraints geben an, dass die angeforderte Größe der natürlichen Größe des Elements entsprechen soll. Ein vertikales StackLayout ruft GetSizeRequest (oder Measure) für seine untergeordneten Elemente mit einer unbegrenzten Höheneinschränkung auf. Ein horizontales Stapellayout ruft GetSizeRequest (oder Measure) für seine untergeordneten Elemente mit einer unbegrenzten Breiteneinschränkung auf. Ein AbsoluteLayout ruft GetSizeRequest (oder Measure) für seine untergeordneten Elemente mit einer unbegrenzten Breiten- und Höheneinschränkung auf.

Der Prozess im Detail

ExploreChildSize zeigt Informationen zu Constraints und Größenanforderungen für ein einfaches Layout.

Ableiten von der Layoutansicht<>

Eine benutzerdefinierte Layoutklasse wird von Layout<View> abgeleitet. Sie hat zwei Aufgaben:

  • Außerkraftsetzen von OnMeasure, um Measure für alle untergeordneten Elemente im Layout aufzurufen Zurückgeben einer angeforderten Größe für das Layout selbst
  • Außerkraftsetzen von LayoutChildren, um Layout für alle untergeordneten Elemente im Layout aufzurufen

Die for- oder foreach-Schleife dieser Außerkraftsetzungen sollte alle untergeordneten Elemente überspringen, deren IsVisible-Eigenschaft auf false festgelegt ist.

OnMeasure wird nicht in jedem Fall aufgerufen. Wenn das übergeordnete Element des Layouts die Größe des Layouts bestimmt (z.B. ein Layout, das eine Seite füllt), wird OnMeasure nicht aufgerufen. Aus diesem Grund kann sich LayoutChildren nicht darauf verlassen, dass die Größe der untergeordneten Elemente beim Aufruf von OnMeasure bestimmt wird. Häufig muss LayoutChildren den Aufruf von Measure selbst für die untergeordneten Elemente des Layouts durchführen. Alternativ können Sie eine Logik zum Zwischenspeichern der Größe implementieren (dieses Thema wird später näher besprochen).

Ein einfaches Beispiel

Das Beispiel VerticalStackDemo enthält eine vereinfachte VerticalStack-Klasse und zeigt, wie diese Klasse verwendet wird.

Vereinfachte vertikale und horizontale Positionierung

Eine der Aufgaben, die VerticalStack ausführen muss, findet während der Außerkraftsetzung von LayoutChildren statt. Die Methode ermittelt anhand der Eigenschaft HorizontalOptions des untergeordneten Elements, wie das untergeordnete Element innerhalb von VerticalStack positioniert werden soll. Sie können stattdessen die statische Methode Layout.LayoutChildIntoBoundingRectaufrufen. Diese Methode ruft Measure für das untergeordnete Element auf und positioniert das untergeordnete Element basierend auf den Eigenschaften HorizontalOptions und VerticalOptions innerhalb des angegebenen Rechtecks.

Aufheben einer Validierung

Häufig wirkt sich eine Änderung der Eigenschaft eines Elements darauf aus, wie das Element im Layout angezeigt wird. Das Layout muss ungültig gemacht werden, um ein neues Layout zu starten.

VisualElement definiert die geschützte Methode InvalidateMeasure, die üblicherweise vom Handler für geänderte Eigenschaften einer bindbaren Eigenschaft aufgerufen wird, deren Änderung sich auf die Größe des Elements auswirkt. Die Methode InvalidateMeasure löst ein MeasureInvalidated-Ereignis aus.

Die Klasse Layout definiert eine ähnliche geschützte Methode InvalidateLayout, die von einer Layout-Ableitung für jede Änderung aufgerufen werden sollte, die sich auf die Position und Größe ihrer untergeordneten Elemente auswirkt.

Regeln für die Layoutprogrammierung

  1. Eigenschaften, die durch Layout<T>-Ableitungen definiert werden, sollten durch bindbare Eigenschaften gestützt werden, und die Handler für geänderte Eigenschaften sollten InvalidateLayout aufrufen.

  2. Eine Layout<T>-Ableitung, die angefügte bindbare Eigenschaften definiert, sollte OnAdded außer Kraft setzen, um einen Handler für geänderte Eigenschaften zu ihren untergeordneten Elementen hinzuzufügen, und OnRemoved außer Kraft setzen, um diesen Handler zu entfernen. Der Handler sollte diese angefügten bindbaren Eigenschaften auf Änderungen überprüfen und ggf. mit einem Aufruf von InvalidateLayout reagieren.

  3. Ein Layout<T> Derivat, das einen Cache mit untergeordneten Größen implementiert, sollte den Cache überschreiben InvalidateLayout und OnChildMeasureInvalidated löschen, wenn diese Methoden aufgerufen werden.

Ein Layout mit Eigenschaften

Die WrapLayout Klasse im Xamarin.FormsBook.Toolkit geht davon aus, dass alle untergeordneten Elemente dieselbe Größe haben, und umschließt die untergeordneten Elemente von einer Zeile (oder Spalte) in die nächste. Die Klasse definiert eine Orientation-Eigenschaft wie StackLayoutsowie ColumnSpacing- und RowSpacing-Eigenschaften wie Grid. Darüber hinaus wird mit dieser Klasse die Größe von untergeordneten Elementen zwischengespeichert.

Im Beispiel PhotoWrap wird ein WrapLayout mit einer ScrollView kombiniert, um Fotos anzuzeigen.

Dimensionen ohne Einschränkungen sind nicht zulässig!

Die UniformGridLayout in der Xamarin.FormsBook.Toolkit-Bibliothek soll alle untergeordneten Elemente in sich anzeigen. Aus diesem Grund können keine Dimensionen ohne Einschränkungen verarbeitet werden. Wird eine solche Dimension erkannt, wird eine Ausnahme ausgelöst.

Das UniformGridLayout wird im Beispiel PhotoGrid veranschaulicht:

Screenshot des Uniform Grid Layouts von Photo Grid

Überlappende untergeordnete Elemente

Bei einer Layout<T>-Ableitung ist eine Überlappung von untergeordneten Elementen möglich. Die untergeordneten Elemente werden jedoch in ihrer Reihenfolge in der Children-Auflistung gerendert, nicht in der Reihenfolge, in der ihre Layout-Methoden aufgerufen werden.

Die Klasse Layout definiert zwei Methoden, mit denen Sie ein untergeordnetes Element innerhalb der Auflistung verschieben können:

  • LowerChild , um ein untergeordnetes Element an den Anfang der Sammlung zu verschieben
  • RaiseChild , um ein untergeordnetes Element an das Ende der Sammlung zu verschieben

Bei überlappenden untergeordneten Elementen werden untergeordnete Elemente am Ende der Auflistung oberhalb von untergeordneten Elementen am Anfang der Auflistung angezeigt.

Die OverlapLayout -Klasse in der Xamarin.FormsBook.Toolkit-Bibliothek definiert eine angefügte Eigenschaft, um die Renderreihenfolge anzugeben und somit eine ihrer untergeordneten Elemente über den anderen anzuzeigen. Dies wird im Beispiel StudentCardFile veranschaulicht:

" von

Weitere angefügte bindbare Eigenschaften

Die CartesianLayout -Klasse in der Xamarin.FormsBook.Toolkit-Bibliothek definiert angefügte bindungsfähige Eigenschaften, um zwei Point Werte und einen Dickenwert BoxView anzugeben, und bearbeitet Elemente so, dass sie Linien ähneln.

Im Beispiel UnitCube wird diese Klasse für einen 3D-Würfel verwendet.

Layout und LayoutTo

Eine Layout<T>-Ableitung kann LayoutTo anstelle von Layout aufrufen, um das Layout zu animieren. Die AnimatedCartesianLayout -Klasse macht dies, und das AnimatedUnitCube-Beispiel veranschaulicht dies.