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

垂直和水平定位簡化
在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調用的結果,以便您可以簡化後續調用。但正確地做到這一點需要了解失效的過程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章