Erstellen eines benutzerdefinierten Layouts in Xamarin.Forms
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 Layout
Layout<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:
- Während des Layoutzyklus ist jedes übergeordnete Element für den Aufruf der Methode für die
Measure
untergeordneten Elemente verantwortlich. - 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:
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:
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:
Erstellen Sie eine von der
Layout<View>
-Klasse abgeleitete Klasse. Weitere Informationen finden Sie unter Erstellen eines WrapLayouts.[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.
Überschreiben Sie die
OnMeasure
-Methode, um dieMeasure
-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. Fehler beim Aufrufen derLayout
-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
OnMeasure
LayoutChildren
überschreiben, überspringen Sie alle untergeordneten Elemente, derenIsVisible
Eigenschaft auffalse
festgelegt ist. Dadurch wird sichergestellt, dass das benutzerdefinierte Layout keinen Platz für unsichtbare untergeordnete Elemente lässt.[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.[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 Page
hinzufü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
WrapLayout
berechnet. 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 dieWrapLayout
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.PositiveInfinity
festgelegt 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 WrapLayout
dem 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 WrapLayout
hinzu. Dies ergibt die in den folgenden Screenshots gezeigte Darstellung:
Die folgenden Screenshots zeigen, WrapLayout
nachdem es in Querformat 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äufig Aufrufe ihrer LayoutChildren
-Methode, wenn jedes Image
Element eine neue Größe erhält, die auf dem geladenen Foto basiert.