使用网格排列视图

已完成

假设要生成在 7x5 网格中显示图像的页面。 可以使用多个水平和垂直 StackLayout 容器来创建此页面。 但是由于多个版式面板的内存和进程要求,可能编写代码会很繁琐,并且可能引起性能问题。 Grid 版式面板对于同时需要行和列的 UI 而言是更好的选择。 在本单元中,你将学习如何定义 Grid 以及如何在其单元格中放置视图。

什么是网格?

Grid 是由行和列构成的版式面板。 下图显示了网格的概念视图。

Illustration showing an example grid with rows and columns of boxes, with one box spanning multiple rows and columns.

将视图放置在通过行和列相交而创建的单元格中。 例如,如果创建具有三列两行的 Grid,则视图将有六个单元格。 行和列的大小可以不同,或者可以将它们设为自动调整大小以适应放入其中的子级的大小。 子视图可以占据单个单元格或跨多个单元格。 此灵活性使得 Grid 成为许多应用的根版式面板的不错选择。

如何指定网格的行和列

创建 Grid 时,可以单独定义每一行和每一列。 每行的高度和每列的宽度可完全由你控制。 每个 Grid 具有可定义网格形状的 RowDefinitionColumnDefinition 对象的集合。 请使用 RowDefinitionColumnDefinition 的实例填充这些集合,它们表示 UI 中的行或列。

这里有两个代码片段,显示 RowDefinitionColumnDefinition 的类定义:

public sealed class RowDefinition : ...
{
    ...
    public GridLength Height { get; set; }
}
public sealed class ColumnDefinition : ...
{
    ...
    public GridLength Width { get; set; }
}

请注意,RowDefinition 具有一个名为 Height 的属性,ColumnDefinition 具有一个名为 Width 的属性。 请使用这些属性来设置行的高度和列的宽度,如以下部分所述。

什么是 GridLength?

WidthHeight 属性的数据类型为 GridLength。 此类型包含两个属性:GridUnitTypeValue。 下面是一个代码片段,显示一部分类型定义。

public struct GridLength
{
    ...
    public GridUnitType GridUnitType { get; }
    public double Value { get; }
}

可以将属性 GridUnitType 设为以下值之一:

  • Absolute
  • Auto
  • Star

现在仔细查看每个值。

绝对 GridUnitType

Absolute 指定该行或列的大小应当固定。 使用 Value 属性来表示大小。 以下示例显示如何使用 C# 将行的高度设为 100 个设备单位的固定大小。 注意 GridLength 构造函数的使用方式,该构造函数采用数字值。 此构造函数会自动将 GridUnitType 设置为 Absolute

var row = new RowDefinition() { Height = new GridLength(100) };

在 XAML 中,只需提供数字值。 XAML 分析程序将调用类型转换器来创建 GridLength 实例。 以下示例通过 XAML 显示相同内容:

<RowDefinition Height="100" />

自动 GridUnitType

Auto 自动调整行或列的大小,以适应子视图大小。 Grid 扫描该行或列中的所有子视图、选择最大的视图,然后将行或列的大小调整到足以适合该子视图的大小。 通过代码创建行定义时,会忽略数值。 可以使用任何值。 以下示例显示如何使用 C# 将行的高度设为自动调整大小。 请注意,我们任意选择了一个值,1

var row = new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) };

如果使用 XAML,则使用值 Auto。 以下示例通过 XAML 显示相同内容。

<RowDefinition Height="Auto" />

Star GridUnitType

Star 提供按比例调整大小的功能。 在按比例调整大小时,总可用空间和每行或每列要求的比例决定了大小。 人们通常将此称为“比例缩放”而不是“按比例调整大小”。

现在来了解如何在网格中对行使用按比例调整大小。

  1. 确定可用空间:Grid 扫描不使用比例缩放的所有行。 它将所有这些行的高度相加,然后从 Grid 本身的高度中减去该总和。 通过此计算可得到可用于所有经过比例缩放的行的空间量。

  2. 划分可用空间:Grid 随后会根据各个行的 Value 设置,为经比例缩放的所有行划分可用空间。 将 Value 属性视为一个乘数,它为所有经过比例缩放的行确定比率。 例如,如果有两个经过比例缩放的行,都以 1 作为乘数,则可用空间将在它们之间平均分配。 但如果其中一行将 2 作为“值”,则它获得的空间将是另一行的两倍。

以下示例显示如何将行的高度设置为 2 Star(C# 中):

var row = new RowDefinition() { Height = new GridLength(2, GridUnitType.Star) };

在 XAML 中,使用 * 符号来表示比例缩放。 将值和 * 合并在单个字符串中,然后类型转换器会创建 GridLength。 下面是 XAML 中的相同示例。

<RowDefinition Height="2*" />

网格集合

使用 RowDefinitionColumnDefinition 定义行和列后,可以将其添加到 Grid。 请使用 GridRowDefinitionsColumnDefinitions 集合属性。 填充这些集合的操作最常在 XAML 中完成。

此示例演示如何定义四个行并使用 RowDefinitions 属性将其添加到 Grid

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="100" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="1*" />
        <RowDefinition Height="2*" />
    </Grid.RowDefinitions>
    ...
</Grid>

此定义可以缩短为:

<Grid RowDefinitions="100, Auto, 1*, 2*">
    ...
</Grid>

用于定义列的 XAML 与此 XAML 相似,除非使用 ColumnDefinitions 并设置宽度。

在运行时,此 XAML 会生成带有四个行的 Grid。 第一行具有 100 个设备单位的高度固定。 第二行的高度与行中最高视图的高度一致。 第三和第四行使用比例缩放,这表示它们会占用剩余可用空间,并基于其各自的 Value 乘数按比例分得空间。 由于第三行是 1* 而第四行是 2*,因此第四行的高度是第三行的两倍。

行和列的默认大小

行和列的默认大小是 1*。 例如,请看以下 XAML。

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    ...
</Grid>

此定义可以缩短为:

<Grid RowDefinitions="*, *, *" ColumnDefinitions="*, *">
    ...
</Grid>

由于未指定任何行或列的大小,因此 1* 将应用于所有行和列。 在运行时,此配置将创建一致的 Grid,表示所有行的高度都相同,并且所有列的宽度都相同。

如何将视图添加到网格

将视图添加到 Grid,即是将其添加到特定单元格。 单元格位于行和列相交的位置。 若要将视图放置在某单元格中,需要知道该单元格的位置。 使用行号和列号的组合来确定单元格。

行和列的编号

行和列的编号从零开始。 原始点在左上角。 下图显示四行两列的 Grid 的编号。

Illustration showing a grid with four rows and two columns. The numbering is shown for each row and column. Starting from the top-left box at column zero and row zero, to the bottom-right box at column 1 and row 3.

例如,如果要将视图添加到右下角的单元格,则可以说该视图的位置是 row 3 column 1

通过使用附加的属性将视图添加到网格

将视图添加到网格时,需要一种方法来指定视图的行号和列号。 一种解决方案是定义 View 基类上的 RowColumn 属性,以便可以直接在视图上指定位置。 此方法有用,但它不是最有效的方法。 视图不会始终在 Grid 中,因此有时不需要这些属性。 更好的方法是使用附加属性。

附加属性在某个类中进行定义,但在其他类型的对象上进行设置。

可将附加属性视为键值对的集合,该集合是视图的一部分。 将视图添加到 Grid 时,请指定行和列。 通过使用附加属性,可以添加一个键值对,它包含键 Grid.Row 和用于指定行号的值。 当 Grid 准备好放置视图时,它将检查集合以确定是否有一个名为 Grid.Row 的键。 如果有,Grid 会使用其值来放置视图。

此示例显示如何创建 Grid 以及使用附加属性添加视图:

<Grid RowDefinitions="*, *, *" ColumnDefinitions="*, *">

    <BoxView Grid.Row="1" Grid.Column="0" Color="Navy" />
    
</Grid>

在此示例中,Grid.Row=1Grid.Column=0 是已添加到 BoxView 的内部集合的键值对。 Grid 使用这些值来确定视图的放置位置。 这是在设备上运行应用程序时 Grid 的外观效果。

Illustration showing a Grid with three rows and two columns. A BoxView is displayed in the second row of the first column.

如何让视图占据多行或多列的空间

这里还有两个需要注意的附加属性:Grid.RowSpanGrid.ColumnSpan。 这些属性指定视图占据的行数或列数。 例如,请看以下 XAML。

<Grid RowDefinitions="*, *, *" ColumnDefinitions="*, *">

    <BoxView Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Color="Navy" />
    
</Grid>

请注意,此示例将 ColumnSpan 设置为 2。 此视图占据从 Column 0 开始的两列。 这是在设备上运行应用程序时 Grid 的外观效果。

Illustration showing a Grid with three rows and two columns. A BoxView is positioned in the second row of the first column and spans both columns.

知识检查

1.

Star GridUnitType 的用途是什么?