天天看點

第二十六章:自定義布局(七)

垂直和水準定位簡化

在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的預設Horizo​​ntalOptions和VerticalOptions設定,否則LayoutChildIntoBoundingRegion方法本身需要使用該Rectangle值的Width和Height屬性對子項調用GetSizeRequest。這是它知道如何将子項定位在傳遞給方法調用的Rectangle中提供的區域内的唯一方法。

這意味着當使用LayoutChildIntoBoundingRegion方法時,VerticalLayout類可以在每個布局周期中的每個子節點上調用GetSizeRequest三次。

此外,正如VerticalLayout多次在其子節點上調用GetSizeRequest,有時使用不同的參數一樣,VerticalLayout的父節點可能會使用不同的參數多次調用VerticalLayout上的GetSizeRequest,進而導緻更多的OnSizeRequest調用。

調用GetSizeRequest不應該有任何副作用。調用不會導緻設定任何其他屬性,并且應該僅基于特定寬度和高度限制來檢索資訊。是以,可以比布局更自由地調用GetSizeRequest,這實際上會影響元素的大小和位置。

但如果您不需要,請不要調用GetSizeRequest。要在螢幕上顯示元素,不需要調用GetSizeRequest。隻需要布局。

在你自己的布局類中,最好“盲目地”處理OnSizeRequest調用,而不試圖弄清楚調用的來源,或者為什麼參數是它們是什麼,或者用不同的參數獲得多個調用意味着什麼。

但是,您的布局類可以緩存OnSizeRequest調用的結果,以便您可以簡化後續調用。但正确地做到這一點需要了解失效的過程。

繼續閱讀