选择 Xamarin.Forms 布局

Xamarin.Forms 布局类允许在应用程序中排列和分组 UI 控件。 选择布局类需要了解布局如何定位其子元素,以及布局如何调整其子元素的大小。 此外,可能还需要嵌套布局来创建所需的布局。

下图显示了可以使用主要 Xamarin.Forms 布局类实现的典型布局:

Xamarin.Forms 中的主要布局类

StackLayout

StackLayout 在水平或垂直方向上组织一维堆栈中的元素。 该 Orientation 属性指定元素的方向,默认方向为 VerticalStackLayout 通常用于在页面上排列 UI 的子部分。

以下 XAML 演示如何创建包含三个 Label 对象的垂直 StackLayout

<StackLayout Margin="20,35,20,25">
    <Label Text="The StackLayout has its Margin property set, to control the rendering position of the StackLayout." />
    <Label Text="The Padding property can be set to specify the distance between the StackLayout and its children." />
    <Label Text="The Spacing property can be set to specify the distance between views in the StackLayout." />
</StackLayout>

StackLayout 中,如果未显式设置某元素的大小,则该元素将展开以填充可用宽度,如果 Orientation 属性设置为 Horizontal,则填充可用高度。

StackLayout 通常用作包含其他子布局的父布局。 但是,不应使用 StackLayout 通过 StackLayout 对象的组合来重现 Grid 布局。 以下代码显示了此错误做法的示例:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Details.HomePage"
             Padding="0,20,0,0">
    <StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Name:" />
            <Entry Placeholder="Enter your name" />
        </StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Age:" />
            <Entry Placeholder="Enter your age" />
        </StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Occupation:" />
            <Entry Placeholder="Enter your occupation" />
        </StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Address:" />
            <Entry Placeholder="Enter your address" />
        </StackLayout>
    </StackLayout>
</ContentPage>

这比较浪费,因为会执行不需要的布局计算。 相反,可用通过使用 Grid 更好地实现所需的布局。

提示

使用 StackLayout 时,确保只有一个子元素设置为 LayoutOptions.Expands。 此属性可确保指定子级会占用 StackLayout 可以向它提供的最大空间,而多次执行这些计算比较浪费。

有关详细信息,请参阅 Xamarin.Forms StackLayout

网格

Grid 用于显示行和列中的元素,这些元素可以有比例大小或绝对大小。 可使用 RowDefinitionsColumnDefinitions 属性指定网格的行和列。

要定位特定 Grid 单元格中的元素,请使用 Grid.ColumnGrid.Row 附加属性。 要使元素跨多个行和列,请使用 Grid.RowSpanGrid.ColumnSpan 附加属性。

注意

不应将 Grid 布局与表混淆,该布局也不用于显示表格数据。 与 HTML 表不同,Grid 用于布局内容。 若要显示表格数据,请考虑使用 ListViewCollectionView TableView

以下 XAML 演示如何创建包含两行两列的 Grid

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="50" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>    
    <Label Text="Column 0, Row 0"
           WidthRequest="200" />
    <Label Grid.Column="1"
           Text="Column 1, Row 0" />
    <Label Grid.Row="1"
           Text="Column 0, Row 1" />
    <Label Grid.Column="1"
           Grid.Row="1"
           Text="Column 1, Row 1" />
</Grid>

在此示例中,大小调整的工作原理如下:

  • 每行的显式高度为 50 个独立于设备的单位。
  • 第一列的宽度设置为 Auto,因此满足其子列所需的宽度。 在本例中,其宽度为 200 个与设备无关的单位以满足第一个 Label 的宽度。

可以使用自动调整大小在列或行中分配空间,从而使列和行的大小适合其内容。 可通过将 RowDefinition 的高度或 ColumnDefinition 的宽度设置为 Auto 来达成此目的。 按比例调整大小还可以用于按加权比例在网格的行和列之间分配可用空间。 可以通过将 RowDefinition 的高度或 ColumnDefinition 的宽度设置为使用 * 运算符的值来达成此目的。

注意

尽量确保将尽可能少的行和列设置为 Auto 大小。 每个自动调整大小的行或列都会导致布局引擎执行额外布局计算。 应在可能时使用固定大小的行和列。 或者,将行和列设置为使用 GridUnitType.Star 枚举值按比例占用空间量。

有关详细信息,请参阅Xamarin.Forms 网格

FlexLayout

FlexLayout 类似于 StackLayout,它在堆栈中水平或垂直显示子元素。 但是,如果单个行或列中容纳太多元素,则 FlexLayout 也可以换行其子元素,并且还可以更精细地控制其子元素的大小、方向和对齐方式。

以下 XAML 演示如何创建在单个列中显示其视图的 FlexLayout

<FlexLayout Direction="Column"
            AlignItems="Center"
            JustifyContent="SpaceEvenly">
    <Label Text="FlexLayout in Action" />
    <Button Text="Button" />
    <Label Text="Another Label" />
</FlexLayout>

在此示例中,布局的工作方式如下:

  • Direction 属性设置为 Column,这将导致 FlexLayout 的子项排列在单列项中。
  • AlignItems 属性设置为 Center,这将使每个项水平居中。
  • JustifyContent 属性设置为 SpaceEvenly,这将在所有项之间、第一个项上方和最后一个项下方平均分配所有剩余的垂直空间。

有关详细信息,请参阅 Xamarin.Forms FlexLayout

RelativeLayout

RelativeLayout 用来对元素进行位置和大小调整(相当于布局属性或同级元素而言)。 默认情况下,元素位于布局的左上角。 RelativeLayout 用于创建可根据设备大小按比例缩放的 UI。

RelativeLayout 中,位置和大小被指定为约束。 约束具有 FactorConstant 属性,可用于将位置和大小定义为其他对象属性的倍数(或分数)加上一个常数。 此外,常数可以是负数。

注意

RelativeLayout 支持将元素定位到其自身边界之外。

以下 XAML 显示了如何排列 RelativeLayout中的元素:

<RelativeLayout>
    <BoxView Color="Blue"
             HeightRequest="50"
             WidthRequest="50"
             RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0}"
             RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0}" />
    <BoxView Color="Red"
             HeightRequest="50"
             WidthRequest="50"
             RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=.85}"
             RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0}" />
    <BoxView x:Name="pole"
             Color="Gray"
             WidthRequest="15"
             RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=.75}"
             RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=.45}"
             RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=.25}" />
    <BoxView Color="Green"
             RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=.10, Constant=10}"
             RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=.2, Constant=20}"
             RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView, ElementName=pole, Property=X, Constant=15}"
             RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=pole, Property=Y, Constant=0}" />
</RelativeLayout>

在此示例中,布局的工作方式如下:

  • 蓝色 BoxView 的显式大小为 50x50 个设备无关单位。 它放置在布局的左上角,这是默认位置。
  • 红色 BoxView 的显式大小为 50x50 个设备无关单位。 它放置在布局的右上角。
  • 灰色 BoxView 的显式宽度为 15 个设备无关单位,其高度设置为其父级高度的 75%。
  • 绿色 BoxView 未给出显式大小。 其位置是相对于名为 poleBoxView 设置的。

警告

尽可能避免使用 RelativeLayout。 它会导致 CPU 不得不执行显著更多的工作。

有关详细信息,请参阅 Xamarin.Forms RelativeLayout

AbsoluteLayout

AbsoluteLayout 用于使用显式值或相对于布局大小的值来定位元素和调整元素大小。 位置由子级的左上角相对于 AbsoluteLayout 的左上角指定。

AbsoluteLayout 应视为特殊用途的布局,仅在你可以设置子级的大小或元素的大小不影响其他子级的位置时使用。 此布局的标准用法是创建覆盖层,该覆盖层使用其他控件覆盖页面,可能是为了防止用户与页面上的常规控件交互。

重要

HorizontalOptionsVerticalOptions 属性对 AbsoluteLayout 的子级不起作用。

AbsoluteLayout 中,AbsoluteLayout.LayoutBounds 附加的属性用于指定元素的水平位置、垂直位置、宽度和高度。 此外,AbsoluteLayout.LayoutFlags 附加属性指定了如何解释布局边界。

以下 XAML 显示如何在 AbsoluteLayout 中排列元素:

<AbsoluteLayout Margin="40">
    <BoxView Color="Red"
             AbsoluteLayout.LayoutFlags="PositionProportional"
             AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100"
             Rotation="30" />
    <BoxView Color="Green"
             AbsoluteLayout.LayoutFlags="PositionProportional"
             AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100"
             Rotation="60" />
    <BoxView Color="Blue"
             AbsoluteLayout.LayoutFlags="PositionProportional"
             AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100" />
</AbsoluteLayout>

在此示例中,布局的工作方式如下:

  • 每个 BoxView 都具有 100x100 的显式大小,并显示在相同的位置(水平居中)。
  • 红色 BoxView 旋转 30 度,绿色 BoxView 旋转 60 度。
  • 在每个 BoxView 上,AbsoluteLayout.LayoutFlags 附加属性设置为 PositionProportional,表示该位置与考虑宽度和高度后的剩余空间成正比。

注意

应尽可能避免使用 AbsoluteLayout.AutoSize 属性,因为它将导致布局引擎执行额外的布局计算。

有关详细信息,请参阅 Xamarin.Forms AbsoluteLayout

输入透明度

每个视觉元素都有一个 InputTransparent 属性,用于定义元素是否接收输入。 其默认值为 false,确保元素接收输入。

在布局类上设置此属性时,其值将传输到子元素。 因此,将 InputTransparent 属性设置为 true 布局类将导致布局中的所有元素不接收输入。

布局性能

若要获取最佳可能布局性能,请遵循优化布局性能中的准则。

此外,还可以通过使用布局压缩来提升页面呈现性能,布局压缩从可视化树中删除指定的布局。 有关详细信息,请参阅布局压缩