垂直和水平定位簡化
在VerticalStack中,LayoutChildren覆蓋的末尾是一個switch語句,它有助於根據子級的HorizontalOptions屬性設置水平定位每個子級。 這是整個方法:
public class VerticalStack : Layout<View>
{
__
protected override void LayoutChildren(double x, double y, double width, double height)
{
// Enumerate through all the children.
foreach (View child in Children)
{
// Skip the invisible children.
if (!child.IsVisible)
continue;
// Get the child's requested size.
SizeRequest childSizeRequest = child.GetSizeRequest(width, Double.PositiveInfinity);
// Initialize child position and size.
double xChild = x;
double yChild = y;
double childWidth = childSizeRequest.Request.Width;
double childHeight = childSizeRequest.Request.Height;
// Adjust position and size based on HorizontalOptions.
switch (child.HorizontalOptions.Alignment)
{
case LayoutAlignment.Start:
break;
case LayoutAlignment.Center:
xChild += (width - childWidth) / 2;
break;
case LayoutAlignment.End:
xChild += (width - childWidth);
break;
case LayoutAlignment.Fill:
childWidth = width;
break;
}
// Layout the child.
child.Layout(new Rectangle(xChild, yChild, childWidth, childHeight));
// Get the next child’s vertical position.
y += childHeight;
}
}
}
在編寫佈局時,基於其HorizontalOptions和VerticalOptions設置將子項定位在矩形內是相當頻繁的。 出於這個原因,Layout 類包含一個公共靜態方法,它爲您執行:
public static void LayoutChildIntoBoundingRegion(VisualElement child, Rectangle region)
您可以重寫LayoutChildren方法以使用此輔助方法,如下所示:
protected override void LayoutChildren(double x, double y, double width, double height)
{
// Enumerate through all the children.
foreach (View child in Children)
{
// Skip the invisible children.
if (!child.IsVisible)
continue;
// Get the child's requested size.
SizeRequest childSizeRequest = child.GetSizeRequest(width, Double.PositiveInfinity);
double childHeight = childSizeRequest.Request.Height;
// Layout the child.
LayoutChildIntoBoundingRegion(child, new Rectangle(x, y, width, childHeight));
// Calculate the next child vertical position.
y += childHeight;
}
}
這是一個相當簡化!但是,由於此調用在本章的其他佈局類中使用,請記住它等同於調用子的Layout方法。
請注意,傳遞給LayoutChildIntoBoundingRegion的矩形包含子項可以駐留的整個區域。在這種情況下,Rectangle構造函數的width參數是傳遞給LayoutChildren的width參數,它是VerticalLayout本身的寬度。但Rectangle構造函數的height參數是特定子項所需的高度,可從GetSizeRequest獲得。
除非子項具有Fill的默認HorizontalOptions和VerticalOptions設置,否則LayoutChildIntoBoundingRegion方法本身需要使用該Rectangle值的Width和Height屬性對子項調用GetSizeRequest。這是它知道如何將子項定位在傳遞給方法調用的Rectangle中提供的區域內的唯一方法。
這意味着當使用LayoutChildIntoBoundingRegion方法時,VerticalLayout類可以在每個佈局週期中的每個子節點上調用GetSizeRequest三次。
此外,正如VerticalLayout多次在其子節點上調用GetSizeRequest,有時使用不同的參數一樣,VerticalLayout的父節點可能會使用不同的參數多次調用VerticalLayout上的GetSizeRequest,從而導致更多的OnSizeRequest調用。
調用GetSizeRequest不應該有任何副作用。調用不會導致設置任何其他屬性,並且應該僅基於特定寬度和高度約束來檢索信息。因此,可以比佈局更自由地調用GetSizeRequest,這實際上會影響元素的大小和位置。
但如果您不需要,請不要調用GetSizeRequest。要在屏幕上顯示元素,不需要調用GetSizeRequest。只需要佈局。
在你自己的佈局類中,最好“盲目地”處理OnSizeRequest調用,而不試圖弄清楚調用的來源,或者爲什麼參數是它們是什麼,或者用不同的參數獲得多個調用意味着什麼。
但是,您的佈局類可以緩存OnSizeRequest調用的結果,以便您可以簡化後續調用。但正確地做到這一點需要了解失效的過程。