第十七章:掌握网格(一)

简介:

Grid是一种强大的布局机制,可将其子项组织为单元格的行和列。起初,Grid似乎与HTML表类似,但有一个非常重要的区别:HTML表是为演示目的而设计的,而Grid仅用于布局。例如,网格中没有标题的概念,并且没有内置功能来在单元格周围绘制框或使用分隔线分隔行和列。 Grid的优势在于使用三个高度和宽度设置选项指定单元格尺寸。
正如您所见,StackLayout非常适合一维儿童收藏。尽管可以在StackLayout中嵌套StackLayout以容纳第二维并模仿表,但结果通常会出现对齐问题。然而,Grid专为二维儿童阵列而设计。正如您将在本章末尾看到的那样,Grid对于管理适应纵向和横向模式的布局也非常有用。

基本网格

可以使用代码或XAML中的子节点定义和填充网格,但XAML方法更容易和更清晰,因此到目前为止更常见。
XAML中的网格
在XAML中定义时,Grid几乎总是具有固定数量的行和列。 Grid定义通常以两个重要属性开头,名为RowDefinitions(RowDefinition对象的集合)和ColumnDefinitions(ColumnDefinition对象的集合)。 这些集合包含Grid中每行的一个RowDefinition和每列的一个ColumnDefinition,它们定义Grid的行和列特征。
网格可以由单行或单列组成(在这种情况下,它不需要两个定义集合中的一个),甚至只需要一个单元格。
RowDefinition具有GridLength类型的Height属性,ColumnDefinition具有Width属性,也是GridLength类型。 GridLength结构根据GridUnitType枚举指定行高或列宽,该枚举有三个成员:

  • 绝对 - 宽度或高度是与设备无关的单位中的值(XAML中的数字)
  • 自动 - 宽度或高度根据单元格内容自动调整(XAML中的“自动”)
  • 按比例分配星级剩余宽度或高度(XAML中带有“*”的数字)

这是SimpleGridDemo项目中XAML文件的前半部分:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SimpleGridDemo.SimpleGridDemoPage">
 
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    iOS="0, 20, 0, 0" />
    </ContentPage.Padding>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="100" />
            <RowDefinition Height="2*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
    __
    </Grid>
</ContentPage>

该网格有四行两列。第一行的高度是“自动” - 意味着高度是根据占据第一行的所有元素的最大高度计算的。第二行是100个与设备无关的单位高度。
使用“*”(发音为“star”)的两个高度设置需要一些额外的解释:此特定网格的总高度是页面的高度减去iOS上的填充设置。在内部,Grid根据该行的内容确定第一行的高度,并且它知道第二行的高度为100.它从它自己的高度中减去这两个高度,并在第三行中按比例分配剩余高度和第四行基于星形设置中的数字。第三行是第四行高度的两倍。
两个ColumnDefinition对象都将Width设置为“”,这与“1 ”相同,这意味着屏幕的宽度在两列之间平均分配。
您将从第14章“绝对布局”中回忆一下,AbsoluteLayout类定义了两个附加的可绑定属性和四个静态Set和Get方法,这些方法允许程序在代码或XAML中指定AbsoluteLayout子项的位置和大小。
网格非常相似。 Grid类定义了四个附加的可绑定属性,用于指定Grid的子节点占用的一个或多个单元格:

  • Grid.RowProperty-从零开始的行;默认值为0
  • Grid.ColumnProperty-从零开始的列; 默认值为0
  • Grid.RowSpanProperty - 子跨越的行数; 默认值为1
  • Grid.ColumnSpanProperty - 子跨越的列数; 默认值为1

所有四个属性都定义为int类型。
例如,要在代码中指定名为view的Grid子项驻留在特定的行和列中,可以调用:

view.SetValue(Grid.RowProperty, 2);
view.SetValue(Grid.ColumnProperty, 1);

这些是从零开始的行号和列号,因此将子项分配给第三行和第二列。
Grid类还定义了八种静态方法,用于在代码中简化设置和获取这些属性:

  • Grid.SetRow 和 Grid.GetRow
  • Grid.SetColumn 和 Grid.GetColumn
  • Grid.SetRowSpan 和 Grid.GetRowSpan
  • Grid.SetColumnSpan 和 Grid.GetColumnSpan

这相当于您刚刚看到的两个SetValue调用:

Grid.SetRow(view, 2);
Grid.SetColumn(view, 1);

正如您在学习AbsoluteLayout时所了解的那样,这些静态Set和Get方法是使用Grid的子节点上的SetValue和GetValue调用实现的。 例如,以下是如何在Grid类中定义SetRow:

public static void SetRow(BindableObject bindable, int value)
{
     bindable.SetValue(Grid.RowProperty, value);
}

您无法在XAML中调用这些方法,因此您可以使用以下属性在Grid的子级上设置附加的可绑定属性:

  • Grid.Row
  • Grid.Column
  • Grid.RowSpan
  • Grid.ColumnSpan

这些XAML属性实际上并不是由Grid类定义的,但XAML解析器知道它必须引用Grid定义的关联附加可绑定属性。
您不需要在Grid的每个子项上设置所有这些属性。 如果子节点只占用一个单元格,则不要设置Grid.RowSpan或Grid.ColumnSpan,因为默认值为1. Grid.Row和Grid.Column属性的默认值为0,因此您不需要 如果子项占据第一行或第一列,则设置值。 但是,为了清楚起见,本书中的代码通常会显示这两个属性的设置。 为了节省空间,这些属性通常会出现在XAML列表的同一行中。
这是SimpleGridDemo的完整XAML文件:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SimpleGridDemo.SimpleGridDemoPage">
 
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    iOS="0, 20, 0, 0" />
    </ContentPage.Padding>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="100" />
            <RowDefinition Height="2*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Label Text="Grid Demo"
               Grid.Row="0" Grid.Column="0"
               FontSize="Large"
               HorizontalOptions="End" />
        <Label Text="Demo the Grid"
               Grid.Row="0" Grid.Column="1"
               FontSize="Small"
               HorizontalOptions="End"
               VerticalOptions="End" />
        <Image BackgroundColor="Gray"
               Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
            <Image.Source>
                <OnPlatform x:TypeArguments="ImageSource"
                            iOS="Icon-60.png"
                            Android="icon.png"
                            WinPhone="Assets/StoreLogo.png" />
            </Image.Source>
        </Image>
        <BoxView Color="Green"
                 Grid.Row="2" Grid.Column="0" />
        <BoxView Color="Red"
                 Grid.Row="2" Grid.Column="1" Grid.RowSpan="2" />
        <BoxView Color="Blue"
                 Opacity="0.5"
                 Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" />
    </Grid>
</ContentPage>

具有不同FontSize设置的两个Label元素占据第一行的两列。 该行的高度由最高元素控制。 HorizontalOptions和VerticalOptions的设置可以将子项定位在单元格中。
第二行的高度为100个与设备无关的单元。 该行由显示具有灰色背景的应用程序图标的Image元素占用。 Image元素跨越该行的两列。
底部的两行由三个BoxView元素占用,一个跨越两行,另一个跨越两列,这些在右下角的单元格中重叠:
2018_09_29_171622
屏幕截图确认第一行的大小与大型Label的高度相同;第二行是100个与设备无关的单位高;并且第三和第四行占据所有剩余空间。第三排是第四排的两倍。两列宽度相等,将整个网格分成两半。红色和蓝色的BoxView元素在右下角的单元格中重叠,但蓝色的BoxView显然位于红色的顶部,因为它的不透明度设置为0.5,结果为紫色。
由于白色背景,蓝色半透明BoxView的左半部分在iPhone和Windows 10移动设备上比在Android手机上轻。
如您所见,Grid的子节点可以共享单元格。子项在XAML文件中出现的顺序是将子项放入Grid中的顺序,后来的子项看起来就像是在早期子项之上(并且模糊了)。
您会注意到一点间隙似乎将背景透过的行和列分开。这由两个Grid属性控制:
RowSpacing-默认值为6
TolumnSpacing-默认值为6
如果要关闭该空间,可以将这些属性设置为0,如果希望窥视颜色不同,则可以设置Grid的BackgroundColor属性。您还可以使用网格上的“填充”设置在网格内部围绕其周边添加空间。
您现在已经了解了Grid定义的所有公共属性和方法。
在继续之前,让我们用SimpleGridDemo进行几个实验。首先,注释掉或删除网格顶部附近的整个RowDefinitions和ColumnDefinitions部分,然后重新部署该程序。这是你会看到的:
2018_09_29_171738
如果未定义自己的RowDefinition和ColumnDefinition对象,则Grid会在将视图添加到Children集合时自动生成它们。 但是,默认的RowDefinition和ColumnDefinition是“*”(星号),这意味着现在四行平均分为四分之一屏幕,每个单元格占总网格的八分之一。
这是另一个实验。 恢复RowDefinitions和ColumnDefinitions部分,并将Grid自身的HorizontalOptions和VerticalOptions属性设置为Center。 默认情况下,这两个属性是Fill,这意味着Grid填充其容器。 以下是Center发生的情况:
2018_09_29_171916
第三行仍然是底行高度的两倍,但现在底行的高度基于BoxView的默认HeightRequest,即40。
将Grid放入StackLayout时,您会看到类似的效果。 您还可以将StackLayout放在网格单元格中,或者放入网格单元格中的另一个网格中,但不要使用此技术:嵌套网格和其他布局越深,嵌套布局对性能的影响就越大。

目录
相关文章
|
1月前
|
JavaScript 前端开发 API
10 个纤细的数据网格:为您的项目选择合适的数据网格
10 个纤细的数据网格:为您的项目选择合适的数据网格
24 0
MIKE 21 教程 1.2 网格搭建界面介绍之点线面要素的高阶处理 (Mesh Generator 工具)
MIKE 21 教程 1.2 网格搭建界面介绍之点线面要素的高阶处理 (Mesh Generator 工具)
技术分享 | ANSYS高级几何处理与网格应用技巧
Space Claim、排油烟机几何处理、流体域抽取;ANSYS Meshing、实际案例网格划分
技术分享 | ANSYS高级几何处理与网格应用技巧
|
存储 运维 监控
一个开关就让服务网格变快 —— 概述篇
作为业内首个全托管Istio兼容的阿里云服务网格产品ASM,一开始从架构上就保持了与社区、业界趋势的一致性,控制平面的组件托管在阿里云侧,与数据面侧的用户集群独立。ASM产品是基于社区Istio定制实现的,在托管的控制面侧提供了用于支撑精细化的流量管理和安全管理的组件能力。通过托管模式,解耦了Istio组件与所管理的K8s集群的生命周期管理,使得架构更加灵活,提升了系统的可伸缩性。从2022年4月
一个开关就让服务网格变快 —— 概述篇
|
架构师 数据管理 数据挖掘
【数据网格】数据网格 101:入门所需的一切
【数据网格】数据网格 101:入门所需的一切
|
数据采集 分布式计算 数据可视化
【数据架构】数据网格解释
【数据架构】数据网格解释
|
人工智能 Kubernetes 监控
谈谈我对服务网格的理解
服务网格作为一种用来管理应用服务通信的基础核心技术,为应用服务间的调用带来了安全、可靠、快速、应用无感知的流量路由、安全、可观测能力。
谈谈我对服务网格的理解
|
存储 SQL 架构师
数据网格简史
数据网格简史
150 0
数据网格简史
|
自然语言处理 Kubernetes 安全
服务网格 ASM 回顾总结:最终用户如何使用服务网格?
本文不打算回顾 Istio 或是阿里云服务网格 ASM 的变化或趋势,我们来聊一聊阿里云 ASM 服务网格,它的最终用户是如何使用服务网格的。
268 4
服务网格 ASM 回顾总结:最终用户如何使用服务网格?
|
自然语言处理 Kubernetes 安全
服务网格 ASM 年终总结:最终用户如何使用服务网格?
本文不打算回顾 Istio 或是阿里云服务网格 ASM 的变化或趋势,我们来聊一聊阿里云 ASM 服务网格,它的最终用户是如何使用服务网格的。
服务网格 ASM 年终总结:最终用户如何使用服务网格?