第十四章:绝对布局(一)

简介:

在Xamarin.Forms中,布局的概念包含了可以在屏幕上组合各种视图的所有方式。 这是类层次结构,显示从Layout派生的所有类:
System.Object

BindableObject
    Element
        VisualElement
            View
                Layout
                    ContentView
                        Frame
                    ScrollView
                    Layout<T>
                        AbsoluteLayout
                        Grid
                        RelativeLayout
                        StackLayout
                        

你已经看过ContentView,Frame和ScrollView(所有这些都有一个你可以设置为一个子节点的Content属性),你已经看到了StackLayout,它继承了Layout 中的Children属性并显示了它的子节点垂直或水平堆叠。 Grid和RelativeLayout实现了一些复杂的布局模型,并将在以后的章节中进行探讨。 AbsoluteLayout是本章的主题。
起初,AbsoluteLayout类似乎实现了一个相当原始的布局模型 - 当程序员需要单独调整大小并定位屏幕上的每个元素时,这个模型可以追溯到不太好的图形用户界面。然而,你会发现AbsoluteLayout还采用了比例定位和尺寸调整功能,有助于将这种古老的布局模型带入现代。
使用AbsoluteLayout,到目前为止您学习的许多关于布局的规则不再适用:当View是ContentPage或StackLayout的子项时,如此重要的Horizo​​ntalOptions和VerticalOptions属性在View是子项时绝对没有效果一个AbsoluteLayout。程序必须为AbsoluteLayout的每个子项分配与设备无关的坐标中的特定位置。还可以为孩子分配特定大小或允许孩子自己调整大小。
您可以在代码或XAML中使用AbsoluteLayout。 无论哪种方式,您都会遇到一个您尚未看到的功能,这是BindableObject和BindableProperty提供的支持的另一部分。 此新功能是附加的可绑定属性。 这是一种特殊类型的可绑定属性,由一个类(在本例中为AbsoluteLayout)定义,但在其他对象(AbsoluteLayout的子节点)上设置。

代码中的AbsoluteLayout

您可以像使用StackLayout一样将子视图添加到AbsoluteLayout的Children集合中:

absoluteLayout.Children.Add(child);

但是,您还有其他选择。 AbsoluteLayout类将其Children属性重新定义为AbsoluteLayout.IAbsoluteList 类型,其中包括两个额外的Add方法,允许您指定子项相对于AbsoluteLayout左上角的位置。 您可以选择指定孩子的大小。
要指定位置和大小,请使用Rectangle值。 Rectangle是一个结构,您可以使用接受Point和Size值的构造函数创建Rectangle值:

Point point = new Point(x, y);
Size size = new Size(width, height);
Rectangle rect = new Rectangle(point, size);

或者,您可以将x,y,width和height参数直接传递给Rectangle构造函数:

Rectangle rect = new Rectangle(x, y, width, height);

然后,您可以使用另一种Add方法将视图添加到AbsoluteLayout的Children集合中:

absoluteLayout.Children.Add(child, rect);

x和y值指示子视图的左上角相对于设备无关坐标中AbsoluteLayout父项的左上角的位置。 如果您希望孩子自己调整大小,则只能使用没有Size值的Point值:

absoluteLayout.Children.Add(child, point);

这是一个名为AbsoluteDemo的程序中的一个小演示:

public class AbsoluteDemoPage : ContentPage
{
    public AbsoluteDemoPage()
    {
        AbsoluteLayout absoluteLayout = new AbsoluteLayout
        { 
            Padding = new Thickness(50)
        };
        absoluteLayout.Children.Add(
            new BoxView
            {
                Color = Color.Accent
            },
            new Rectangle(0, 10, 200, 5));
        absoluteLayout.Children.Add(
            new BoxView
            {
                Color = Color.Accent
            },
            new Rectangle(0, 20, 200, 5));
        absoluteLayout.Children.Add(
            new BoxView
            {
                Color = Color.Accent
            },
            new Rectangle(10, 0, 5, 65));
        absoluteLayout.Children.Add(
            new BoxView
            {
                Color = Color.Accent
            },
            new Rectangle(20, 0, 5, 65));
        absoluteLayout.Children.Add(
            new Label
            {
                Text = "Stylish Header",
                FontSize = 24
            },
            new Point(30, 25));
        absoluteLayout.Children.Add(
            new Label
            {
                FormattedText = new FormattedString
                {
                    Spans = 
                    {
                        new Span
                        {
                            Text = "Although the "
                        },
                        new Span
                        {
                            Text = "AbsoluteLayout",
                            FontAttributes = FontAttributes.Italic
                        },
                        new Span 
                        {
                            Text = " is usually employed for purposes other " +
                                   "than the display of text using "
                        },
                        new Span
                        {
                            Text = "Label",
                            FontAttributes = FontAttributes.Italic
                        },
                        new Span
                        {
                            Text = ", obviously it can be used in that way. " +
                                   "The text continues to wrap nicely " +
                                   "within the bounds of the container " +
                                   "and any padding that might be applied."
                        }
                    }
                }
            },
            new Point(0, 80));
        this.Content = absoluteLayout;
    }
}

四个BoxView元素在顶部形成一个重叠的十字形图案以引出标题,然后是一段文字。 程序定位和调整所有BoxView元素,而它只是定位两个Label视图,因为它们自己调整大小:
2018_08_28_114830
需要进行一些试验和错误才能使四个BoxView元素的大小和标题文本的大小大致相同。但请注意BoxView元素重叠:AbsoluteLayout允许您以非常自由的方式重叠视图,这对于StackLayout来说根本不可能(或者不使用变换,这将在后面的章节中介绍)。
AbsoluteLayout的一大缺点是你需要自己设定定位坐标或在运行时计算它们。任何未明确调整大小的内容(例如两个Label视图)都会在页面布局时计算自身的大小。但是那个尺寸直到那时才可用。如果您想在第二个Label之后添加另一个段落,您会使用什么坐标?
实际上,您可以通过在AbsoluteLayout中放置StackLayout(或ScrollView内的StackLayout)然后将Label视图放入其中来定位多段文本。布局可以嵌套。
您可以推测,使用AbsoluteLayout比使用StackLayout更困难。通常,让Xamarin.Forms和其他布局类为您处理大部分布局复杂性要容易得多。但对于一些特殊用途,AbsoluteLayout是理想的选择。
与所有可视元素一样,AbsoluteLayout默认将其Horizo​​ntalOptions和VerticalOptions属性设置为Fill,这意味着AbsoluteLayout填充其容器。使用Horizo​​ntalOptions和VerticalOptions的其他设置,AbsoluteLayout将自身的大小调整为其内容的大小,但也有一些例外:尝试在AbsoluteDemo中给出AbsoluteLayout
编程BackgroundColor,以便您可以准确地看到它在屏幕上占据的空间。它通常填充整个页面,但是如果设置Horizo​​ntalOptions和VerticalOptions属性
对于中心的AbsoluteLayout,您将看到AbsoluteLayout为其自身计算的大小包括内容和填充,但只包含文本段落的一行。
确定AbsoluteLayout中视觉元素的大小可能很棘手。下面的ChessboardFixed程序演示了一种简单的方法。程序名称后缀为Fixed,因为棋盘中所有方块的位置和大小都是在构造函数中设置的。构造函数无法预测屏幕的大小,因此它可以任意设置每个方块的大小为35个单位,如类顶部的squareSize常量所示。此值应足够小,以使棋盘适合Xamarin.Forms支持的任何设备的屏幕。
请注意,AbsoluteLayout是居中的,因此它的大小可以容纳其所有子节点。电路板本身有浅黄色,浅黄色,然后在每个其他方形位置显示32个深绿色BoxView元素:

public class ChessboardFixedPage : ContentPage
{
    public ChessboardFixedPage()
    {
        const double squareSize = 35;
        AbsoluteLayout absoluteLayout = new AbsoluteLayout
        {
            BackgroundColor = Color.FromRgb(240, 220, 130),
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        };
        for (int row = 0; row < 8; row++)
        {
            for (int col = 0; col < 8; col++)
            {
                // Skip every other square.
                if (((row ^ col) & 1) == 0)
                    continue;
                BoxView boxView = new BoxView
                { 
                    Color = Color.FromRgb(0, 64, 0) 
                };
                Rectangle rect = new Rectangle(col * squareSize, 
                                               row * squareSize, 
                                               squareSize, squareSize);
                absoluteLayout.Children.Add(boxView, rect);
            }
        }
        this.Content = absoluteLayout;
    }
}

对row和col变量的异或计算仅在row或col变量为奇数但两者都不是奇数时才会创建BoxView。 这是结果:
2018_08_28_115242

目录
相关文章
|
9月前
鬼刀画风扁平化粒子炫动引导页美化源码
鬼刀画风扁平化粒子炫动引导页美化源码
58 5
鬼刀画风扁平化粒子炫动引导页美化源码
|
人工智能 vr&ar 图形学
次世代建模纹理贴图怎么做?
高端的引擎技术、材质贴图技术、渲染技术,使得次世代模型有着比肩电影画面的视觉效果,且是实时渲染。而且次世代模型有着面数高、贴图精度高、运用法线贴图描绘物体表面凹凸变化、高光贴图表现物体材质反光、实时光影等特点。
165 2
|
安全 容器
由圣杯布局引发的思考
今天在MDN看到块格式化上下文有点不以为然,关键是它写的高深莫测,读不懂... 于是下午想试试圣杯布局的时候,终究还是逃不过它。🤣 这里不介绍圣杯布局的历史,这样的文章网上不知道多少篇,我来写写千篇一律中的亮点吧,哈哈。
68 0
|
小程序
如何做一个俄罗斯方块6:形状停靠
在处理形状停靠之前,有一点儿东西需要了解,就是已经停靠的方块和正在下落的方块不是一种方块,如图,红色的表示的是已经停靠的方块,绿色的表示下落的绿色方块的作用是展示当前下落的形状,红色方块的作用是标识出哪些位置已经摆放了方块。
142 0
经典圣杯布局
经典圣杯布局
110 0
|
容器
【D3.js 学习总结】20、D3布局-捆图
# d3.layout.bundle() ![](https://img.alicdn.com/tps/TB19Q82LXXXXXawXVXXXXXXXXXX-500-500.png) 下图是航班查询网站全球航班雷达(FlightRadar24)显示的今日长三角地区的飞机飞行图: ![](https://img.alicdn.com/tps/TB1jp4WLXXXXXaraXXX
3626 0
|
JavaScript Android开发
|
JavaScript Android开发