Erstellen eines benutzerdefinierten Layouts in Xamarin.Forms

Beispiel herunterladen Das Beispiel herunterladen

Xamarin.Forms definiert fünf Layoutklassen– StackLayout, AbsoluteLayout, RelativeLayout, Grid und FlexLayout, und jede ordnet die untergeordneten Klassen auf unterschiedliche Weise an. Manchmal ist es jedoch erforderlich, Seiteninhalte mit einem Layout zu organisieren, das nicht von bereitgestellt wird Xamarin.Forms. In diesem Artikel wird erläutert, wie eine benutzerdefinierte Layoutklasse geschrieben wird, und es wird eine ausrichtungsabhängige WrapLayout-Klasse veranschaulicht, die ihre untergeordneten Elemente horizontal über die Seite anordnet und dann die Anzeige der nachfolgenden untergeordneten Elemente in zusätzliche Zeilen umschließt.

In Xamarin.Formsleiten alle Layoutklassen von der Layout<T> -Klasse ab und beschränken den generischen Typ auf View und seine abgeleiteten Typen. Die -Klasse leitet sich wiederum Layout<T> von der Layout -Klasse ab, die den Mechanismus zum Positionieren und Dimensionieren untergeordneter Elemente bereitstellt.

Jedes visuelle Element ist für die Bestimmung seiner eigenen bevorzugten Größe verantwortlich, die als angeforderte Größe bezeichnet wird. Page, und LayoutLayout<View> abgeleitete Typen sind für die Bestimmung des Standorts und der Größe ihres untergeordneten Oder untergeordneten Typs im Verhältnis zu sich selbst verantwortlich. Daher umfasst das Layout eine Beziehung zwischen übergeordnetem und untergeordnetem Element, bei der das übergeordnete Element bestimmt, wie groß die untergeordneten Elemente sein sollen, aber versucht, die angeforderte Größe des untergeordneten Elements zu berücksichtigen.

Zum Erstellen eines benutzerdefinierten Layouts ist ein gründliches Verständnis der Xamarin.Forms Layout- und Ungültigkeitszyklen erforderlich. Diese Zyklen werden nun erörtert.

Layout

Das Layout beginnt am oberen Rand der visuellen Struktur mit einer Seite und durchläuft alle Verzweigungen der visuellen Struktur, um jedes visuelle Element auf einer Seite zu umfassen. Elemente, die übergeordnete Elemente für andere Elemente sind, sind für die Größenanpassung und Positionierung ihrer untergeordneten Elemente in Bezug auf sich selbst verantwortlich.

Die VisualElement -Klasse definiert eine Measure Methode, die ein Element für Layoutvorgänge misst, und eine Layout Methode, die den rechteckigen Bereich angibt, in dem das Element gerendert wird. Wenn eine Anwendung gestartet und die erste Seite angezeigt wird, beginnt ein Layoutzyklus , der zuerst aus Measure Aufrufen und dann Layout Aufrufen besteht, für das Page Objekt:

  1. Während des Layoutzyklus ist jedes übergeordnete Element für den Aufruf der Methode für die Measure untergeordneten Elemente verantwortlich.
  2. Nachdem die untergeordneten Elemente gemessen wurden, ist jedes übergeordnete Element für das Aufrufen der Methode für seine Layout untergeordneten Elemente verantwortlich.

Dieser Zyklus stellt sicher, dass jedes visuelle Element auf der Seite Aufrufe der Measure Methoden und Layout empfängt. Der Prozess ist im folgenden Diagramm dargestellt:

Xamarin.Forms Layoutzyklus

Hinweis

Beachten Sie, dass Layoutzyklen auch für eine Teilmenge der visuellen Struktur auftreten können, wenn sich etwas ändert, um das Layout zu beeinflussen. Dies schließt Elemente ein, die einer Auflistung hinzugefügt oder entfernt werden, z. B. in einer StackLayout, einer Änderung der IsVisible Eigenschaft eines Elements oder einer Änderung der Größe eines Elements.

Jede Xamarin.Forms Klasse mit einer Content oder einer Children Eigenschaft verfügt über eine überschreibbare LayoutChildren Methode. Benutzerdefinierte Layoutklassen, die von Layout<View> abgeleitet werden, müssen diese Methode überschreiben und sicherstellen, dass die Measure Methoden und Layout für alle untergeordneten Elemente des Elements aufgerufen werden, um das gewünschte benutzerdefinierte Layout bereitzustellen.

Darüber hinaus muss jede Klasse, die von Layout der -Methode abgeleitet ist oder Layout<View> überschreiben OnMeasure muss, wobei eine Layoutklasse die erforderliche Größe bestimmt, indem sie die Measure Methoden ihrer untergeordneten Elemente aufruft.

Hinweis

Elemente bestimmen ihre Größe anhand von Einschränkungen, die angeben, wie viel Speicherplatz für ein Element innerhalb des übergeordneten Elements des Elements verfügbar ist. Einschränkungen, die an die Measure Methoden und OnMeasure übergeben werden, können zwischen 0 und reichen Double.PositiveInfinity. Ein Element ist eingeschränkt oder vollständig eingeschränkt, wenn es einen Aufruf seiner Measure Methode mit nicht unendlichen Argumenten empfängt . Das Element ist auf eine bestimmte Größe beschränkt. Ein Element ist nicht eingeschränkt oder teilweise eingeschränkt, wenn es einen Aufruf seiner Measure Methode mit mindestens einem Argument erhält, das gleich ist Double.PositiveInfinity . Die unendliche Einschränkung kann als Hinweis auf die Autosisierung angesehen werden.

Invalidierung

Invalidation ist der Prozess, bei dem eine Änderung in einem Element auf einer Seite einen neuen Layoutzyklus auslöst. Elemente gelten als ungültig, wenn sie nicht mehr die richtige Größe oder Position aufweisen. Wenn sich beispielsweise die FontSize Eigenschaft eines Button ändert, wird als Button ungültig angegeben, da es nicht mehr die richtige Größe aufweist. Das Ändern der Button Größe kann dann einen Welleneffekt von Änderungen im Layout über den Rest einer Seite haben.

Elemente ungültig, indem sie die -Methode aufrufen, in der InvalidateMeasure Regel, wenn sich eine Eigenschaft des Elements ändert, was zu einer neuen Größe des Elements führen kann. Diese Methode löst das MeasureInvalidated Ereignis aus, das das übergeordnete Element verarbeitet, um einen neuen Layoutzyklus auszulösen.

Die Layout -Klasse legt einen Handler für das Ereignis für jedes untergeordnete Element fest, das MeasureInvalidated seiner Content Eigenschaft oder Children Auflistung hinzugefügt wird, und trennt den Handler, wenn das untergeordnete Element entfernt wird. Daher wird jedes Element in der visuellen Struktur mit untergeordneten Elementen benachrichtigt, wenn eines der untergeordneten Elemente die Größe ändert. Das folgende Diagramm veranschaulicht, wie eine Änderung der Größe eines Elements in der visuellen Struktur Änderungen verursachen kann, die die Struktur in die Höhe bringen:

Ungültige Elemente in der visuellen Struktur

Die -Klasse versucht jedoch, Layout die Auswirkungen einer Änderung der Größe eines untergeordneten Elements auf das Layout einer Seite einzuschränken. Wenn das Layout größeneinschränkt ist, wirkt sich eine änderung der untergeordneten Größe nicht auf etwas aus, das höher ist als das übergeordnete Layout in der visuellen Struktur. In der Regel wirkt sich eine Änderung der Größe eines Layouts jedoch darauf aus, wie das Layout seine untergeordneten Elemente anordnet. Daher wird bei jeder Änderung der Größe eines Layouts ein Layoutzyklus für das Layout gestartet, und das Layout erhält Aufrufe seiner OnMeasure Methoden und LayoutChildren .

Die Layout -Klasse definiert auch eine InvalidateLayout Methode, die einen ähnlichen Zweck wie die InvalidateMeasure -Methode hat. Die InvalidateLayout -Methode sollte immer dann aufgerufen werden, wenn eine Änderung vorgenommen wird, die sich darauf auswirkt, wie das Layout seine untergeordneten Positionen und Größen angibt. Beispielsweise ruft die Layout -Klasse die InvalidateLayout -Methode auf, wenn einem Layout ein untergeordnetes Element hinzugefügt oder daraus entfernt wird.

Kann InvalidateLayout überschrieben werden, um einen Cache zu implementieren, um wiederholte Aufrufe der Measure Methoden der untergeordneten Layoutelemente zu minimieren. Durch Das Überschreiben der InvalidateLayout -Methode wird eine Benachrichtigung darüber bereitgestellt, wenn untergeordnete Elemente dem Layout hinzugefügt oder aus diesem entfernt werden. Auf ähnliche Weise kann die OnChildMeasureInvalidated -Methode überschrieben werden, um eine Benachrichtigung bereitzustellen, wenn eine der untergeordneten Elemente des Layouts die Größe ändert. Bei beiden Methodenüberschreibungen sollte ein benutzerdefiniertes Layout reagieren, indem der Cache gelöscht wird. Weitere Informationen finden Sie unter Berechnen und Zwischenspeichern von Layoutdaten.

Erstellen eines benutzerdefinierten Layouts

Der Prozess zum Erstellen eines benutzerdefinierten Layouts sieht wie folgt aus:

  1. Erstellen Sie eine von der Layout<View>-Klasse abgeleitete Klasse. Weitere Informationen finden Sie unter Erstellen eines WrapLayouts.

  2. [optional] Fügen Sie Eigenschaften hinzu, die durch bindungsfähige Eigenschaften unterstützt werden, für alle Parameter, die für die Layoutklasse festgelegt werden sollen. Weitere Informationen finden Sie unter Hinzufügen von Eigenschaften, die von bindbaren Eigenschaften unterstützt werden.

  3. Überschreiben Sie die OnMeasure -Methode, um die Measure -Methode für alle untergeordneten Elemente des Layouts aufzurufen, und geben Sie eine angeforderte Größe für das Layout zurück. Weitere Informationen finden Sie unter Überschreiben der OnMeasure-Methode.

  4. Überschreiben Sie die LayoutChildren -Methode, um die Layout -Methode für alle untergeordneten Elemente des Layouts aufzurufen. Fehler beim Aufrufen der Layout -Methode für jedes untergeordnete Element in einem Layout führen dazu, dass das untergeordnete Element nie eine richtige Größe oder Position erhält, sodass das untergeordnete Element auf der Seite nicht sichtbar wird. Weitere Informationen finden Sie unter Überschreiben der LayoutChildren-Methode.

    Hinweis

    Wenn Sie untergeordnete Elemente in und OnMeasureLayoutChildren überschreiben, überspringen Sie alle untergeordneten Elemente, deren IsVisible Eigenschaft auf falsefestgelegt ist. Dadurch wird sichergestellt, dass das benutzerdefinierte Layout keinen Platz für unsichtbare untergeordnete Elemente lässt.

  5. [optional] Überschreiben Sie die Methode, die InvalidateLayout benachrichtigt werden soll, wenn untergeordnete Elemente dem Layout hinzugefügt oder aus diesem entfernt werden. Weitere Informationen finden Sie unter Überschreiben der InvalidateLayout-Methode.

  6. [optional] Überschreiben Sie die Methode, die OnChildMeasureInvalidated benachrichtigt werden soll, wenn eine der untergeordneten Layoutgrößen ändert. Weitere Informationen finden Sie unter Überschreiben der OnChildMeasureInvalidated-Methode.

Hinweis

Beachten Sie, dass die OnMeasure Überschreibung nicht aufgerufen wird, wenn die Größe des Layouts von seinem übergeordneten Element und nicht von den untergeordneten Elementen bestimmt wird. Die Überschreibung wird jedoch aufgerufen, wenn eine oder beide Einschränkungen unendlich sind oder wenn die Layoutklasse Nicht-Standard HorizontalOptions - oder VerticalOptions Eigenschaftswerte aufweist. Aus diesem Grund kann die LayoutChildren Überschreibung nicht von untergeordneten Größen abhängen, die während des Methodenaufrufs OnMeasure abgerufen wurden. Stattdessen LayoutChildren muss die -Methode für die Measure untergeordneten Elemente des Layouts aufgerufen werden, bevor die Layout -Methode aufgerufen wird. Alternativ kann die Größe der untergeordneten Elemente, die in der OnMeasure Überschreibung erhalten wurden, zwischengespeichert werden, um spätere Measure Aufrufe in der LayoutChildren Überschreibung zu vermeiden, aber die Layoutklasse muss wissen, wann die Größen erneut abgerufen werden müssen. Weitere Informationen finden Sie unter Berechnen und Zwischenspeichern von Layoutdaten.

Die Layoutklasse kann dann genutzt werden, indem Sie sie zu einem Pagehinzufügen und dem Layout untergeordnete Elemente hinzufügen. Weitere Informationen finden Sie unter Verwenden des WrapLayouts.

Erstellen eines WrapLayout-Objekts

Die Beispielanwendung veranschaulicht eine ausrichtungsabhängige WrapLayout Klasse, die ihre untergeordneten Elemente horizontal über die Seite anordnet und dann die Anzeige der nachfolgenden untergeordneten Elemente in zusätzliche Zeilen umschließt.

Die WrapLayout Klasse weist denselben Speicherplatz für jedes untergeordnete Element zu, das als Zellengröße bezeichnet wird, basierend auf der maximalen Größe der untergeordneten Elemente. Untergeordnete Elemente, die kleiner als die Zellgröße sind, können in der Zelle basierend auf ihren HorizontalOptions Eigenschaftenwerten und VerticalOptions positioniert werden.

Die WrapLayout Klassendefinition wird im folgenden Codebeispiel gezeigt:

public class WrapLayout : Layout<View>
{
  Dictionary<Size, LayoutData> layoutDataCache = new Dictionary<Size, LayoutData>();
  ...
}

Berechnen und Zwischenspeichern von Layoutdaten

Die LayoutData -Struktur speichert Daten zu einer Auflistung untergeordneter Elemente in einer Reihe von Eigenschaften:

  • VisibleChildCount – Die Anzahl der untergeordneten Elemente, die im Layout sichtbar sind.
  • CellSize – Die maximale Größe aller untergeordneten Elemente, angepasst an die Größe des Layouts.
  • Rows – die Anzahl der Zeilen.
  • Columns – die Anzahl der Spalten.

Das layoutDataCache Feld wird verwendet, um mehrere LayoutData Werte zu speichern. Wenn die Anwendung gestartet wird, werden zwei LayoutData Objekte im Wörterbuch für die layoutDataCache aktuelle Ausrichtung zwischengespeichert – eines für die Einschränkungsargumente für die OnMeasure Überschreibung, und eines für die width Argumente und height für die LayoutChildren Überschreibung. Beim Rotieren des Geräts in die Querformatausrichtung werden die OnMeasure Überschreibung und die LayoutChildren Überschreibung erneut aufgerufen, was dazu führt, dass zwei LayoutData weitere Objekte im Wörterbuch zwischengespeichert werden. Bei der Rückgabe des Geräts in die Hochformatausrichtung sind jedoch keine weiteren Berechnungen erforderlich, da bereits layoutDataCache die erforderlichen Daten vorhanden sind.

Das folgende Codebeispiel zeigt die GetLayoutData -Methode, die die Eigenschaften der LayoutData Strukturierten basierend auf einer bestimmten Größe berechnet:

LayoutData GetLayoutData(double width, double height)
{
  Size size = new Size(width, height);

  // Check if cached information is available.
  if (layoutDataCache.ContainsKey(size))
  {
    return layoutDataCache[size];
  }

  int visibleChildCount = 0;
  Size maxChildSize = new Size();
  int rows = 0;
  int columns = 0;
  LayoutData layoutData = new LayoutData();

  // Enumerate through all the children.
  foreach (View child in Children)
  {
    // Skip invisible children.
    if (!child.IsVisible)
      continue;

    // Count the visible children.
    visibleChildCount++;

    // Get the child's requested size.
    SizeRequest childSizeRequest = child.Measure(Double.PositiveInfinity, Double.PositiveInfinity);

    // Accumulate the maximum child size.
    maxChildSize.Width = Math.Max(maxChildSize.Width, childSizeRequest.Request.Width);
    maxChildSize.Height = Math.Max(maxChildSize.Height, childSizeRequest.Request.Height);
  }

  if (visibleChildCount != 0)
  {
    // Calculate the number of rows and columns.
    if (Double.IsPositiveInfinity(width))
    {
      columns = visibleChildCount;
      rows = 1;
    }
    else
    {
      columns = (int)((width + ColumnSpacing) / (maxChildSize.Width + ColumnSpacing));
      columns = Math.Max(1, columns);
      rows = (visibleChildCount + columns - 1) / columns;
    }

    // Now maximize the cell size based on the layout size.
    Size cellSize = new Size();

    if (Double.IsPositiveInfinity(width))
      cellSize.Width = maxChildSize.Width;
    else
      cellSize.Width = (width - ColumnSpacing * (columns - 1)) / columns;

    if (Double.IsPositiveInfinity(height))
      cellSize.Height = maxChildSize.Height;
    else
      cellSize.Height = (height - RowSpacing * (rows - 1)) / rows;

    layoutData = new LayoutData(visibleChildCount, cellSize, rows, columns);
  }

  layoutDataCache.Add(size, layoutData);
  return layoutData;
}

Die GetLayoutData Methode führt die folgenden Vorgänge aus:

  • Es bestimmt, ob sich ein berechneter LayoutData Wert bereits im Cache befindet, und gibt ihn zurück, wenn er verfügbar ist.
  • Andernfalls werden alle untergeordneten Elemente aufgelistet, die Measure Methode für jedes untergeordnete Element mit unendlicher Breite und Höhe aufgerufen und die maximale untergeordnete Größe bestimmt.
  • Sofern mindestens ein sichtbares untergeordnetes Element vorhanden ist, wird die Anzahl der erforderlichen Zeilen und Spalten berechnet und dann eine Zellgröße für die untergeordneten Elemente basierend auf den Dimensionen von WrapLayoutberechnet. Beachten Sie, dass die Zellgröße in der Regel etwas größer als die maximale Untergeordnete Größe ist, aber auch kleiner sein kann, wenn die WrapLayout für das breiteste Kind nicht breit genug oder groß genug für das größte Kind ist.
  • Der neue LayoutData Wert wird im Cache gespeichert.

Hinzufügen von Eigenschaften, die durch bindungsfähige Eigenschaften unterstützt werden

Die WrapLayout -Klasse definiert ColumnSpacing und RowSpacing Eigenschaften, deren Werte verwendet werden, um die Zeilen und Spalten im Layout zu trennen, und die durch bindungsfähige Eigenschaften unterstützt werden. Die bindungsfähigen Eigenschaften werden im folgenden Codebeispiel gezeigt:

public static readonly BindableProperty ColumnSpacingProperty = BindableProperty.Create(
  "ColumnSpacing",
  typeof(double),
  typeof(WrapLayout),
  5.0,
  propertyChanged: (bindable, oldvalue, newvalue) =>
  {
    ((WrapLayout)bindable).InvalidateLayout();
  });

public static readonly BindableProperty RowSpacingProperty = BindableProperty.Create(
  "RowSpacing",
  typeof(double),
  typeof(WrapLayout),
  5.0,
  propertyChanged: (bindable, oldvalue, newvalue) =>
  {
    ((WrapLayout)bindable).InvalidateLayout();
  });

Der eigenschaftsveränderte Handler jeder bindungsfähigen Eigenschaft ruft die InvalidateLayout -Methode außer Kraft, um einen neuen Layoutdurchlauf für auszulösen WrapLayout. Weitere Informationen finden Sie unter Überschreiben der InvalidateLayout-Methode und Überschreiben der OnChildMeasureInvalidated-Methode.

Überschreiben der OnMeasure-Methode

Die OnMeasure Überschreibung wird im folgenden Codebeispiel gezeigt:

protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
  LayoutData layoutData = GetLayoutData(widthConstraint, heightConstraint);
  if (layoutData.VisibleChildCount == 0)
  {
    return new SizeRequest();
  }

  Size totalSize = new Size(layoutData.CellSize.Width * layoutData.Columns + ColumnSpacing * (layoutData.Columns - 1),
                layoutData.CellSize.Height * layoutData.Rows + RowSpacing * (layoutData.Rows - 1));
  return new SizeRequest(totalSize);
}

Die Überschreibung ruft die GetLayoutData -Methode auf und erstellt ein SizeRequest Objekt aus den zurückgegebenen Daten, wobei auch die RowSpacing Eigenschaftenwerte und ColumnSpacing berücksichtigt werden. Weitere Informationen zur GetLayoutData Methode finden Sie unter Berechnen und Zwischenspeichern von Layoutdaten.

Wichtig

Die Measure Methoden und OnMeasure sollten niemals eine unendliche Dimension anfordern, indem sie einen SizeRequest Wert mit einer Eigenschaft zurückgeben, die auf Double.PositiveInfinityfestgelegt ist. Mindestens eines der Einschränkungsargumente kann OnMeasure jedoch lauten Double.PositiveInfinity.

Überschreiben der LayoutChildren-Methode

Die LayoutChildren Überschreibung wird im folgenden Codebeispiel gezeigt:

protected override void LayoutChildren(double x, double y, double width, double height)
{
  LayoutData layoutData = GetLayoutData(width, height);

  if (layoutData.VisibleChildCount == 0)
  {
    return;
  }

  double xChild = x;
  double yChild = y;
  int row = 0;
  int column = 0;

  foreach (View child in Children)
  {
    if (!child.IsVisible)
    {
      continue;
    }

    LayoutChildIntoBoundingRegion(child, new Rectangle(new Point(xChild, yChild), layoutData.CellSize));
    if (++column == layoutData.Columns)
    {
      column = 0;
      row++;
      xChild = x;
      yChild += RowSpacing + layoutData.CellSize.Height;
    }
    else
    {
      xChild += ColumnSpacing + layoutData.CellSize.Width;
    }
  }
}

Die Überschreibung beginnt mit einem Aufruf der GetLayoutData -Methode und listet dann alle untergeordneten Elemente auf, um sie in der Zelle jedes untergeordneten Elements zu vergrößern und zu positionieren. Dies wird erreicht, indem die LayoutChildIntoBoundingRegion Methode aufgerufen wird, die verwendet wird, um ein untergeordnetes Element in einem Rechteck basierend auf seinen HorizontalOptions - und VerticalOptions -Eigenschaftswerten zu positionieren. Dies entspricht einem Aufruf der -Methode des untergeordneten Layout Elements.

Hinweis

Beachten Sie, dass das an die LayoutChildIntoBoundingRegion -Methode übergebene Rechteck den gesamten Bereich enthält, in dem sich das untergeordnete Element befinden kann.

Weitere Informationen zur GetLayoutData Methode finden Sie unter Berechnen und Zwischenspeichern von Layoutdaten.

Überschreiben der InvalidateLayout-Methode

Die InvalidateLayout Überschreibung wird aufgerufen, wenn untergeordnete Elemente zum Layout hinzugefügt oder aus dem Layout entfernt werden oder wenn eine der Eigenschaften den WrapLayout Wert ändert, wie im folgenden Codebeispiel gezeigt:

protected override void InvalidateLayout()
{
  base.InvalidateLayout();
  layoutInfoCache.Clear();
}

Durch die Überschreibung wird das Layout ungültig und alle zwischengespeicherten Layoutinformationen verworfen.

Hinweis

Um zu beenden, dass die Layout Klasse die InvalidateLayout -Methode aufruft, wenn ein untergeordnetes Element zu einem Layout hinzugefügt oder aus diesem entfernt wird, überschreiben Sie die ShouldInvalidateOnChildAdded Methoden und ShouldInvalidateOnChildRemoved und und geben zurück false. Die Layoutklasse kann dann einen benutzerdefinierten Prozess implementieren, wenn untergeordnete Elemente hinzugefügt oder entfernt werden.

Überschreiben der OnChildMeasureInvalidated-Methode

Die OnChildMeasureInvalidated Überschreibung wird aufgerufen, wenn eines der untergeordneten Layouts die Größe ändert, und wird im folgenden Codebeispiel gezeigt:

protected override void OnChildMeasureInvalidated()
{
  base.OnChildMeasureInvalidated();
  layoutInfoCache.Clear();
}

Durch die Überschreibung wird das untergeordnete Layout ungültig und alle zwischengespeicherten Layoutinformationen verworfen.

Verwenden des WrapLayout

Die WrapLayout Klasse kann genutzt werden, indem sie auf einen Page abgeleiteten Typ platziert wird, wie im folgenden XAML-Codebeispiel veranschaulicht:

<ContentPage ... xmlns:local="clr-namespace:ImageWrapLayout">
    <ScrollView Margin="0,20,0,20">
        <local:WrapLayout x:Name="wrapLayout" />
    </ScrollView>
</ContentPage>

Der entsprechende C#-Code ist unten dargestellt:

public class ImageWrapLayoutPageCS : ContentPage
{
  WrapLayout wrapLayout;

  public ImageWrapLayoutPageCS()
  {
    wrapLayout = new WrapLayout();

    Content = new ScrollView
    {
      Margin = new Thickness(0, 20, 0, 20),
      Content = wrapLayout
    };
  }
  ...
}

Untergeordnete Elemente können dann nach Bedarf hinzugefügt WrapLayout werden. Das folgende Codebeispiel zeigt Image Elemente, die WrapLayoutdem hinzugefügt werden:

protected override async void OnAppearing()
{
    base.OnAppearing();

    var images = await GetImageListAsync();
    if (images != null)
    {
        foreach (var photo in images.Photos)
        {
            var image = new Image
            {
                Source = ImageSource.FromUri(new Uri(photo))
            };
            wrapLayout.Children.Add(image);
        }
    }
}

async Task<ImageList> GetImageListAsync()
{
    try
    {
        string requestUri = "https://raw.githubusercontent.com/xamarin/docs-archive/master/Images/stock/small/stock.json";
        string result = await _client.GetStringAsync(requestUri);
        return JsonConvert.DeserializeObject<ImageList>(result);
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"\tERROR: {ex.Message}");
    }

    return null;
}

Wenn die Seite mit dem WrapLayout angezeigt wird, greift die Beispielanwendung asynchron auf eine JSON-Remotedatei mit einer Liste von Fotos zu, erstellt ein Image Element für jedes Foto und fügt es dem WrapLayouthinzu. Dies ergibt die in den folgenden Screenshots gezeigte Darstellung:

Beispielfotos für das Anwendungsformat

Die folgenden Screenshots zeigen, WrapLayout nachdem es in Querformat gedreht wurde:

Beispiel für die iOS-Anwendungslandschaft ScreenshotBeispiel für die Android-Anwendungslandschaft Screenshot: Beispiel für die UWP-Anwendungslandschaft Screenshot

Die Anzahl der Spalten in jeder Zeile hängt von der Fotogröße, der Bildschirmbreite und der Anzahl der Pixel pro geräteunabhängiger Einheit ab. Die Image Elemente laden die Fotos asynchron, und daher erhält die WrapLayout Klasse häufig Aufrufe ihrer LayoutChildren -Methode, wenn jedes Image Element eine neue Größe erhält, die auf dem geladenen Foto basiert.