Erstellen eines benutzerdefinierten Layouts in Xamarin.Forms
Xamarin.Forms definiert fünf Layoutklassen – StackLayout, AbsoluteLayout, RelativeLayout, Grid und FlexLayout, und jede ordnet die untergeordneten Elemente auf andere Weise an. Manchmal ist es jedoch erforderlich, Seiteninhalte mithilfe eines Layouts zu organisieren, das nicht von Xamarin.Forms. In diesem Artikel wird erläutert, wie Sie eine benutzerdefinierte Layoutklasse schreiben und eine ausrichtungsabhängige WrapLayout-Klasse veranschaulicht, die die untergeordneten Elemente horizontal auf der Seite anordnet, und die Anzeige der nachfolgenden untergeordneten Elemente in zusätzliche Zeilen umschließt.
In Xamarin.Forms, alle Layoutklassen werden von der Layout<T>
Klasse abgeleitet und beschränken den generischen Typ auf View
und die abgeleiteten Typen. Die Klasse wird wiederum Layout<T>
von der Layout
Klasse abgeleitet, die den Mechanismus für die Positionierung und Größenanpassung untergeordneter Elemente bereitstellt.
Jedes visuelle Element ist dafür verantwortlich, seine eigene bevorzugte Größe zu bestimmen, die als angeforderte Größe bezeichnet wird. Page
, Layout
und Layout<View>
abgeleitete Typen sind für die Bestimmung des Standorts und der Größe ihres Untergeordneten oder untergeordneten Elemente relativ zu sich selbst verantwortlich. Daher umfasst das Layout eine Beziehung zwischen übergeordneten und untergeordneten Elementen, wobei das übergeordnete Element bestimmt, wie groß die untergeordneten Elemente sein sollen, aber versucht, die angeforderte Größe des untergeordneten Elements zu berücksichtigen.
Ein gründliches Verständnis der Xamarin.Forms Layout- und Ungültigkeitszyklen ist erforderlich, um ein benutzerdefiniertes Layout zu erstellen. Diese Zyklen werden jetzt erörtert.
Layout
Das Layout beginnt am oberen Rand der visuellen Struktur mit einer Seite und durchläuft alle Zweige der visuellen Struktur, um jedes visuelle Element auf einer Seite einzuschließen. Elemente, die über andere Elemente verfügen, sind für die Größenanpassung und Positionierung ihrer Untergeordneten relativ zu 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 wird und die erste Seite angezeigt wird, beginnt ein Layoutzyklus , der zuerst aus Measure
Aufrufen besteht, und dann Layout
aufruft, für das Page
Objekt:
- Während des Layoutzyklus ist jedes übergeordnete Element dafür verantwortlich, die Methode für die
Measure
untergeordneten Elemente aufzurufen. - Nachdem die untergeordneten Elemente gemessen wurden, ist jedes übergeordnete Element dafür verantwortlich, die Methode für die
Layout
untergeordneten Elemente aufzurufen.
Dieser Zyklus stellt sicher, dass jedes visuelle Element auf der Seite Aufrufe der Measure
Und Layout
Methoden empfängt. Der Prozess wird im folgenden Diagramm dargestellt:
Hinweis
Beachten Sie, dass Layoutzyklen auch in einer Teilmenge der visuellen Struktur auftreten können, wenn sich etwas ändert, um das Layout zu beeinflussen. Dazu gehören Elemente, die einer Auflistung hinzugefügt oder daraus entfernt werden, z. B. in einer StackLayout
Auflistung, eine Änderung der IsVisible
Eigenschaft eines Elements oder eine Ä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>
dieser Methode abgeleitet werden, müssen überschreiben und sicherstellen, dass die und Layout
die Measure
Methoden für alle untergeordneten Elemente des Elements aufgerufen werden, um das gewünschte benutzerdefinierte Layout bereitzustellen.
Darüber hinaus bestimmt jede Klasse, die von Layout
der Methode abgeleitet wird oder Layout<View>
die OnMeasure
Methode überschreiben muss. Dabei bestimmt eine Layoutklasse die Größe, die sie sein muss, indem Aufrufe an die Measure
Methoden der untergeordneten Elemente vorgenommen werden.
Hinweis
Elemente bestimmen ihre Größe basierend auf Einschränkungen, die angeben, wie viel Platz für ein Element innerhalb des übergeordneten Elements verfügbar ist. Einschränkungen, die an die Measure
Methoden übergeben werden, können zwischen 0 und OnMeasure
Double.PositiveInfinity
0 liegen. 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 wird 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 automatische Größenanpassung betrachtet werden.
Invalidierung
Die Ungültigheit ist der Prozess, mit dem eine Änderung in einem Element auf einer Seite einen neuen Layoutzyklus auslöst. Elemente werden als ungültig betrachtet, wenn sie nicht mehr über die richtige Größe oder Position verfügen. Wenn sich beispielsweise die FontSize
Eigenschaft einer Button
Änderung ändert, wird die Button
Eigenschaft als ungültig bezeichnet, da sie nicht mehr über die richtige Größe verfügt. Das Ändern der Button
Größe kann dann auswirkungen auf Änderungen am Layout über den Rest einer Seite haben.
Elemente werden durch Aufrufen der InvalidateMeasure
Methode ungültig, in der Regel, wenn sich eine Eigenschaft des Elements ändert, die zu einer neuen Größe des Elements führen kann. Diese Methode löst das MeasureInvalidated
Ereignis aus, das das übergeordnete Element behandelt, um einen neuen Layoutzyklus auszulösen.
Die Layout
Klasse legt einen Handler für das MeasureInvalidated
Ereignis für jedes untergeordnete Element fest, das 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 seiner untergeordneten Elemente die Größe ändert. Das folgende Diagramm veranschaulicht, wie eine Änderung der Größe eines Elements in der visuellen Struktur Zu änderungen führen kann, die die Struktur aufwellen:
Die Layout
Klasse versucht jedoch, die Auswirkungen einer Änderung der Größe eines untergeordneten Elements auf das Layout einer Seite einzuschränken. Wenn die Größe des Layouts eingeschränkt ist, wirkt sich eine Änderung der untergeordneten Größe nicht auf etwas höher als das übergeordnete Layout in der visuellen Struktur aus. In der Regel wirkt sich eine Änderung der Größe eines Layouts jedoch auf die Anordnung der untergeordneten Elemente des Layouts aus. Daher beginnt jede Änderung der Layoutgröße einen Layoutzyklus für das Layout, und das Layout empfängt Aufrufe an seine OnMeasure
und LayoutChildren
Methoden.
Die Layout
Klasse definiert auch eine InvalidateLayout
Methode, die der Methode einen ähnlichen Zweck hat InvalidateMeasure
. Die InvalidateLayout
Methode sollte immer aufgerufen werden, wenn eine Änderung vorgenommen wird, die sich darauf auswirkt, wie sich die Layoutposition und die Größe der untergeordneten Elemente auswirken. Beispielsweise ruft die Layout
Klasse die InvalidateLayout
Methode auf, wenn ein untergeordnetes Element zu einem Layout hinzugefügt oder daraus entfernt wird.
Dies InvalidateLayout
kann außer Kraft gesetzt werden, um einen Cache zu implementieren, um sich wiederholende Aufrufe der Measure
Methoden der untergeordneten Elemente des Layouts zu minimieren. Wenn die InvalidateLayout
Methode überschrieben wird, wird eine Benachrichtigung darüber bereitgestellt, wann untergeordnete Elemente dem Layout hinzugefügt oder daraus entfernt werden. Ebenso kann die OnChildMeasureInvalidated
Methode außer Kraft gesetzt 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 lautet wie folgt:
Erstellen Sie eine von der
Layout<View>
-Klasse abgeleitete Klasse. Weitere Informationen finden Sie unter Create a WrapLayout.[optional] Fügen Sie Eigenschaften hinzu, die durch bindungsfähige Eigenschaften gesichert werden, für alle Parameter, die für die Layoutklasse festgelegt werden sollen. Weitere Informationen finden Sie unter Add Properties Backed by Bindable Properties.
Überschreiben Sie die Methode, um die
OnMeasure
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.Überschreiben Sie die
LayoutChildren
Methode, um dieLayout
Methode für alle untergeordneten Elemente des Layouts aufzurufen. Wenn dieLayout
Methode für jedes untergeordnete Element in einem Layout nicht aufgerufen wird, erhält das untergeordnete Element niemals eine richtige Größe oder Position, und daher wird das untergeordnete Element nicht auf der Seite sichtbar. Weitere Informationen finden Sie unter Überschreiben der LayoutChildren-Methode.Hinweis
Überspringen Sie beim Aufzählen von untergeordneten Elementen in den
OnMeasure
undLayoutChildren
Außerkraftsetzungen alle untergeordneten Elemente, derenIsVisible
Eigenschaft auffalse
". Dadurch wird sichergestellt, dass das benutzerdefinierte Layout keinen Platz für unsichtbare untergeordnete Elemente erhält.[optional] Überschreiben Sie die
InvalidateLayout
Methode, die benachrichtigt werden soll, wenn untergeordnete Elemente dem Layout hinzugefügt oder daraus entfernt werden. Weitere Informationen finden Sie unter Überschreiben der InvalidateLayout-Methode.[optional] Überschreiben Sie die
OnChildMeasureInvalidated
Methode, die benachrichtigt werden soll, wenn eines der untergeordneten Elemente des Layouts die Größe ändert. Weitere Informationen finden Sie unter Überschreiben der OnChildMeasureInvalidated-Methode.
Hinweis
Beachten Sie, dass die OnMeasure
Außerkraftsetzung nicht aufgerufen wird, wenn die Größe des Layouts durch das übergeordnete Element und nicht durch die untergeordneten Elemente gesteuert wird. Die Außerkraftsetzung wird jedoch aufgerufen, wenn eine oder beide Einschränkungen unendlich sind oder wenn die Layoutklasse nicht standardmäßige HorizontalOptions
oder VerticalOptions
Eigenschaftswerte aufweist. Aus diesem Grund kann die LayoutChildren
Außerkraftsetzung nicht auf untergeordnete Größen angewiesen werden, die während des OnMeasure
Methodenaufrufs abgerufen wurden. LayoutChildren
Stattdessen muss die Measure
Methode für die untergeordneten Elemente des Layouts aufgerufen werden, bevor Sie die Layout
Methode aufrufen. Alternativ kann die Größe der in der OnMeasure
Außerkraftsetzung abgerufenen untergeordneten Elemente zwischengespeichert werden, um spätere Measure
Aufrufe in der LayoutChildren
Außerkraftsetzung zu vermeiden. Die Layoutklasse muss jedoch 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 Page
Hinzufügen und durch Hinzufügen von untergeordneten Elementen zum Layout verwenden. Weitere Informationen finden Sie unter "Verwenden des WrapLayout".
Erstellen eines WrapLayout
Die Beispielanwendung veranschaulicht eine Ausrichtungssensitive WrapLayout
Klasse, die die untergeordneten Elemente horizontal auf der Seite anordnet und anschließend die Anzeige der nachfolgenden untergeordneten Elemente in zusätzliche Zeilen umschließt.
Die WrapLayout
Klasse weist basierend auf der maximalen Größe der untergeordneten Elemente den gleichen Speicherplatz zu, der als Zellengröße bezeichnet wird. Untergeordnete Elemente, die kleiner als die Zellengröße sind, können basierend auf ihren HorizontalOptions
Werten und VerticalOptions
Eigenschaftswerten innerhalb der Zelle 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 Sammlung von untergeordneten Elementen 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 layoutDataCache
Wörterbuch für die aktuelle Ausrichtung zwischengespeichert – eines für die Einschränkungsargumente für die OnMeasure
Außerkraftsetzung und eines für die Außerkraftsetzung und eines für die width
height
LayoutChildren
Außerkraftsetzung. Beim Drehen des Geräts in querformatierte Ausrichtung wird die OnMeasure
Außerkraftsetzung und die LayoutChildren
Außerkraftsetzung erneut aufgerufen, was dazu führt, dass weitere zwei LayoutData
Objekte im Wörterbuch zwischengespeichert werden. Wenn das Gerät jedoch in hochformatiert zurückgegeben wird, sind keine weiteren Berechnungen erforderlich, da die layoutDataCache
bereits erforderlichen Daten enthalten sind.
Das folgende Codebeispiel zeigt die GetLayoutData
Methode, mit der die Eigenschaften der LayoutData
strukturierten Struktur basierend auf einer bestimmten Größe berechnet werden:
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:
- Er 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 aufgezählt, die
Measure
Methode für jedes untergeordnete Element mit einer unendlichen Breite und Höhe abgerufen und die maximale untergeordnete Größe bestimmt. - Vorausgesetzt, es gibt mindestens ein sichtbares untergeordnetes Element, berechnet die Anzahl der erforderlichen Zeilen und Spalten und berechnet dann eine Zellengröße für die untergeordneten Elemente basierend auf den Dimensionen der
WrapLayout
. Beachten Sie, dass die Zellengröße in der Regel etwas breiter ist als die maximale untergeordnete Größe, aber dass sie auch kleiner sein könnte, wenn dieWrapLayout
breiteste untergeordnete Oder für das höchste Kind nicht breit genug ist. - Er speichert den neuen
LayoutData
Wert im Cache.
Hinzufügen von Eigenschaften, die durch bindbare Eigenschaften gesichert 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 gesichert 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 Eigenschaft geänderte Handler jeder bindbaren Eigenschaft ruft die InvalidateLayout
Methodenüberschreibung auf, um einen neuen Layoutdurchlauf für die WrapLayout
. Weitere Informationen finden Sie unter Überschreiben der InvalidateLayout-Methode und Überschreiben der OnChildMeasureInvalidated-Methode.
Überschreiben der OnMeasure-Methode
Die OnMeasure
Außerkraftsetzung 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 Außerkraftsetzung ruft die GetLayoutData
Methode auf und erstellt ein SizeRequest
Objekt aus den zurückgegebenen Daten, wobei auch die RowSpacing
Werte und ColumnSpacing
Eigenschaftswerte berücksichtigt werden. Weitere Informationen zur GetLayoutData
Methode finden Sie unter Calculate and Cache Layout Data.
Wichtig
Die Measure
Methoden OnMeasure
sollten niemals eine unendliche Dimension anfordern, indem sie einen SizeRequest
Wert mit einer Eigenschaft zurückgeben, auf die Double.PositiveInfinity
festgelegt ist. Mindestens eines der Einschränkungsargumente OnMeasure
kann jedoch sein Double.PositiveInfinity
.
Überschreiben der LayoutChildren-Methode
Die LayoutChildren
Außerkraftsetzung 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 Außerkraftsetzung beginnt mit einem Aufruf der GetLayoutData
Methode und listet dann alle untergeordneten Elemente auf und positioniert sie innerhalb der Zelle der einzelnen untergeordneten Elemente. Dies wird durch Aufrufen der LayoutChildIntoBoundingRegion
Methode erreicht, die verwendet wird, um ein untergeordnetes Element innerhalb eines Rechtecks basierend auf seinen HorizontalOptions
Und VerticalOptions
Eigenschaftswerten zu positionieren. Dies entspricht dem Aufrufen 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 Calculate and Cache Layout Data.
Überschreiben der InvalidateLayout-Methode
Die InvalidateLayout
Außerkraftsetzung wird aufgerufen, wenn untergeordnete Elemente dem Layout hinzugefügt oder daraus entfernt werden, oder wenn eine der WrapLayout
Eigenschaften den Wert ändert, wie im folgenden Codebeispiel gezeigt:
protected override void InvalidateLayout()
{
base.InvalidateLayout();
layoutInfoCache.Clear();
}
Durch die Außerkraftsetzung wird das Layout ungültig und alle zwischengespeicherten Layoutinformationen verworfen.
Hinweis
Wenn Sie verhindern möchten, dass die Layout
Klasse die InvalidateLayout
Methode aufruft, wenn ein untergeordnetes Element zu einem Layout hinzugefügt oder daraus entfernt wird, überschreiben Sie die ShouldInvalidateOnChildAdded
Methode ShouldInvalidateOnChildRemoved
und geben Sie diese 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
Außerkraftsetzung wird aufgerufen, wenn eines der untergeordneten Elemente des Layouts die Größe ändert und im folgenden Codebeispiel dargestellt wird:
protected override void OnChildMeasureInvalidated()
{
base.OnChildMeasureInvalidated();
layoutInfoCache.Clear();
}
Die Außerkraftsetzung macht das untergeordnete Layout ungültig und verwirft alle zwischengespeicherten Layoutinformationen.
Verwenden des WrapLayout
Die WrapLayout
Klasse kann genutzt werden, indem sie in einem 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 WrapLayout
Bedarf hinzugefügt werden. Das folgende Codebeispiel zeigt Image
Elemente, die dem WrapLayout
Folgenden 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
Angezeigten angezeigt wird, greift die Beispielanwendung asynchron auf eine REMOTE-JSON-Datei zu, die eine Liste von Fotos enthält, erstellt ein Image
Element für jedes Foto und fügt es der WrapLayout
Datei hinzu. Dies ergibt die in den folgenden Screenshots gezeigte Darstellung:
Die folgenden Screenshots zeigen, WrapLayout
nachdem sie in die Querformatausrichtung gedreht wurde:
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äufige Aufrufe an die LayoutChildren
Methode, da jedes Image
Element basierend auf dem geladenen Foto eine neue Größe erhält.