垂直和水平定位简化
在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调用的结果,以便您可以简化后续调用。但正确地做到这一点需要了解失效的过程。