Xamarin.Forms FlexLayout

使用 FlexLayout 堆叠或包装子视图集合。

Xamarin.FormsFlexLayout 是 Xamarin.Forms 版本 3.0 中的新增功能。 它基于 CSS 灵活框布局模块,通常称为弹性布局弹性框,之所以这样命名,是因为它包含了许多灵活的选项来安排布局中的子元素。

FlexLayout 类似于 Xamarin.FormsStackLayout,因为它可以在堆栈中水平和垂直排列其子级。 但是,如果单个行或列中容纳太多子级,则 FlexLayout 也能够包装其子级,并且还具有许多用于方向、对齐和适应不同屏幕大小的选项。

FlexLayout 派生自 Layout<View>,并继承类型 IList<View>Children 属性。

FlexLayout 定义六个公共可绑定属性以及五个附加的影响其子元素大小、方向和对齐方式的可绑定属性。 (如果不熟悉附加的可绑定属性,请参阅附加属性一文。)下面的“可绑定属性的详细信息”“附加的可绑定属性的详细信息”部分详细介绍了这些属性。 但是,本文首先介绍了 FlexLayout 的一些常见使用方案部分,以更加非正式的方式描述了其中许多属性。 本文末尾介绍如何将 FlexLayoutCSS 样式表合并。

常见使用方案

该示例程序包含多个页面,这些页面介绍了 FlexLayout 的一些常见用途,并允许你试验其属性。

将 FlexLayout 用于简单堆栈

简单堆栈页显示 FlexLayout 如何替代 StackLayout,但使用更简单的标记。 此示例中的所有内容在 XAML 页中定义。 FlexLayout 包含四个子元素:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:FlexLayoutDemos"
             x:Class="FlexLayoutDemos.SimpleStackPage"
             Title="Simple Stack">

    <FlexLayout Direction="Column"
                AlignItems="Center"
                JustifyContent="SpaceEvenly">

        <Label Text="FlexLayout in Action"
               FontSize="Large" />

        <Image Source="{local:ImageResource FlexLayoutDemos.Images.SeatedMonkey.jpg}" />

        <Button Text="Do-Nothing Button" />

        <Label Text="Another Label" />
    </FlexLayout>
</ContentPage>

下面是在 iOS、Android 和通用 Windows 平台上运行的页面:

简单堆栈页面

SimpleStackPage.xaml 文件中显示了 FlexLayout 的三个属性:

  • Direction 属性设置为 FlexDirection 枚举的值。 默认为 Row。 将属性设置为 Column 会导致 FlexLayout 的子元素排列在单个项列中。

    FlexLayout 中的项排列在列中时,FlexLayout 被认为有垂直主轴和水平交叉轴

  • AlignItems 属性的类型为 FlexAlignItems,并指定项在十字轴上对齐的方式。 Center 选项会导致每个项水平居中。

    如果对此任务使用 StackLayout 而不是 FlexLayout,则通过将每个项的 HorizontalOptions 属性分配给 Center 来使所有项居中。 HorizontalOptions 属性不适用于 FlexLayout 的子元素,但单个 AlignItems 属性可实现相同的目标。 如果需要,可以使用 AlignSelf 附加的可绑定属性替代各个项的 AlignItems 属性:

    <Label Text="FlexLayout in Action"
           FontSize="Large"
           FlexLayout.AlignSelf="Start" />
    

    更改后,当阅读顺序从左到右时,此 Label 位于 FlexLayout 的左边缘。

  • JustifyContent 属性的类型为 FlexJustify,并指定项目在主轴上的排列方式。 SpaceEvenly 选项在所有项之间以及第一个项上方和最后一个项下方分配所有剩余的垂直空间。

    如果使用 StackLayout,则需要将每个项的 VerticalOptions 属性分配给 CenterAndExpand 才可达到类似的效果。 但是,CenterAndExpand 选项会为每个项之间分配两倍于第一个项之前和最后一个项之后的空间。 通过将 FlexLayoutJustifyContent 属性设置为 SpaceAround,可以模拟 VerticalOptionsCenterAndExpand 选项。

下面的“可绑定属性”部分详细讨论这些 FlexLayout 属性。

使用 FlexLayout 包装项

示例的“照片包装”页面演示了 FlexLayout 如何将其子级包装到其他行或列。 XAML 文件实例化 FlexLayout 并为其分配两个属性:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FlexLayoutDemos.PhotoWrappingPage"
             Title="Photo Wrapping">
    <Grid>
        <ScrollView>
            <FlexLayout x:Name="flexLayout"
                        Wrap="Wrap"
                        JustifyContent="SpaceAround" />
        </ScrollView>

        <ActivityIndicator x:Name="activityIndicator"
                           IsRunning="True"
                           VerticalOptions="Center" />
    </Grid>
</ContentPage>

FlexLayoutDirection 属性未设置,因此它具有默认设置 Row,这意味着子元素按行排列,主轴是水平的。

Wrap 属性是枚举类型 FlexWrap。 如果行上容纳的项目太多,则此属性设置会导致项换行到下一行。

请注意,FlexLayoutScrollView 的子元素。 如果页面上的行太多,则 ScrollView 具有 Vertical 的默认 Orientation 属性并允许垂直滚动。

JustifyContent 属性在主轴(水平轴)上分配剩余空间,以便每个项被相同数量的空白空间包围。

代码隐藏文件访问示例照片的集合,并将其添加到 FlexLayoutChildren集合:

public partial class PhotoWrappingPage : ContentPage
{
    // Class for deserializing JSON list of sample bitmaps
    [DataContract]
    class ImageList
    {
        [DataMember(Name = "photos")]
        public List<string> Photos = null;
    }

    public PhotoWrappingPage ()
    {
        InitializeComponent ();

        LoadBitmapCollection();
    }

    async void LoadBitmapCollection()
    {
        using (WebClient webClient = new WebClient())
        {
            try
            {
                // Download the list of stock photos
                Uri uri = new Uri("https://raw.githubusercontent.com/xamarin/docs-archive/master/Images/stock/small/stock.json");
                byte[] data = await webClient.DownloadDataTaskAsync(uri);

                // Convert to a Stream object
                using (Stream stream = new MemoryStream(data))
                {
                    // Deserialize the JSON into an ImageList object
                    var jsonSerializer = new DataContractJsonSerializer(typeof(ImageList));
                    ImageList imageList = (ImageList)jsonSerializer.ReadObject(stream);

                    // Create an Image object for each bitmap
                    foreach (string filepath in imageList.Photos)
                    {
                        Image image = new Image
                        {
                            Source = ImageSource.FromUri(new Uri(filepath))
                        };
                        flexLayout.Children.Add(image);
                    }
                }
            }
            catch
            {
                flexLayout.Children.Add(new Label
                {
                    Text = "Cannot access list of bitmap files"
                });
            }
        }

        activityIndicator.IsRunning = false;
        activityIndicator.IsVisible = false;
    }
}

下面是正在运行的程序,从上到下逐步滚动:

“照片包装”页面

使用 FlexLayout 的页面布局

Web 设计中有一个名为“圣杯”的标准布局,因为它是一种非常理想的布局格式,但通常很难完美实现。 布局由页面顶部的页眉和底部的页脚组成,两者都延伸到页面的整个宽度。 占据页面中心的是主要内容,但通常在内容左侧有列式菜单,右侧为补充信息(有时称为侧边栏区域)。 CSS 灵活框布局规范的第 5.4.1 节介绍了如何使用弹性框实现神圣的三位一体布局。

示例的“圣杯布局”页面显示了此布局的一个简单实现,其中使用了一个嵌套在另一个 FlexLayout 中的 FlexLayout。 由于此页面专为纵向模式下的手机设计,内容区域左侧和右侧的区域宽度仅为 50 像素:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FlexLayoutDemos.HolyGrailLayoutPage"
             Title="Holy Grail Layout">

    <FlexLayout Direction="Column">

        <!-- Header -->
        <Label Text="HEADER"
               FontSize="Large"
               BackgroundColor="Aqua"
               HorizontalTextAlignment="Center" />

        <!-- Body -->
        <FlexLayout FlexLayout.Grow="1">

            <!-- Content -->
            <Label Text="CONTENT"
                   FontSize="Large"
                   BackgroundColor="Gray"
                   HorizontalTextAlignment="Center"
                   VerticalTextAlignment="Center"
                   FlexLayout.Grow="1" />

            <!-- Navigation items-->
            <BoxView FlexLayout.Basis="50"
                     FlexLayout.Order="-1"
                     Color="Blue" />

            <!-- Aside items -->
            <BoxView FlexLayout.Basis="50"
                     Color="Green" />

        </FlexLayout>

        <!-- Footer -->
        <Label Text="FOOTER"
               FontSize="Large"
               BackgroundColor="Pink"
               HorizontalTextAlignment="Center" />
    </FlexLayout>
</ContentPage>

此处它正在运行:

“圣杯布局”页面

导航和侧边栏区域通过 BoxView 呈现在左右两侧。

XAML 文件中的第一个 FlexLayout 有一个垂直主轴,并且包含三个在列中排列的子元素。 它们是页眉、页面正文和页脚。 嵌套的 FlexLayout 有一个水平主轴,其中三个子元素在一行。

此程序演示了三个附加的可绑定属性:

  • Order 附加的可绑定属性放在第一个 BoxView 上。 此属性是默认值为 0 的整数。 可以使用此属性更改布局顺序。 通常,开发人员更喜欢页面的内容显示在导航项和项旁的标记中。 将第一个 BoxView 上的 Order 属性设置为小于其他同级的值会导致它显示为行中的第一项。 同样,可以通过将 Order 属性设置为大于其同级的值来确保项最后显示。

  • Basis 附加的可绑定属性在两个 BoxView 项上设置,使其宽度为 50 像素。 此属性的类型为 FlexBasis,该结构定义名为 AutoFlexBasis 类型静态属性,这是默认值。 可以使用 Basis 指定像素大小或百分比,指示项在主轴上占用的空间。 它称为基础,因为它指定项大小,是所有后续布局的基础。

  • Grow 属性在嵌套的 Layout 和表示内容的 Label 子元素上设置。 此属性的类型为 float,默认值为 0。 当设置为正值时,沿主轴的所有剩余空间将分配给该项以及具有正值 Grow的同级。 空间按比例分配给值,有点像 Grid 中的星形规范。

    第一个 Grow 附加属性在嵌套的 FlexLayout 上设置,指示此 FlexLayout 将占用外部 FlexLayout 内所有未使用的垂直空间。 第二个 Grow 附加属性在表示内容的 Label 上设置,指示此内容将占用内部 FlexLayout 内所有未使用的水平空间。

    还有一个类似的 Shrink 附加的可绑定属性,当子级的大小超过 FlexLayout 的大小但不需要包装时,可以使用此属性。

带 FlexLayout 的目录项

示例中的“目录项”页面类似于 CSS 弹性布局框规范第 1.1 节中的 示例 1,只不过它显示了三只猴子的水平滚动系列图片和说明:

“目录项”页面

在这三只猴子中,每只都是一个 FlexLayout,包含在具有明确高度和宽度的 Frame 中,同时也是更大 FlexLayout 的子元素。 在此 XAML 文件中,FlexLayout 子元素的大多数属性都以样式指定,但其中一个属性是隐式样式:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:FlexLayoutDemos"
             x:Class="FlexLayoutDemos.CatalogItemsPage"
             Title="Catalog Items">
    <ContentPage.Resources>
        <Style TargetType="Frame">
            <Setter Property="BackgroundColor" Value="LightYellow" />
            <Setter Property="BorderColor" Value="Blue" />
            <Setter Property="Margin" Value="10" />
            <Setter Property="CornerRadius" Value="15" />
        </Style>

        <Style TargetType="Label">
            <Setter Property="Margin" Value="0, 4" />
        </Style>

        <Style x:Key="headerLabel" TargetType="Label">
            <Setter Property="Margin" Value="0, 8" />
            <Setter Property="FontSize" Value="Large" />
            <Setter Property="TextColor" Value="Blue" />
        </Style>

        <Style TargetType="Image">
            <Setter Property="FlexLayout.Order" Value="-1" />
            <Setter Property="FlexLayout.AlignSelf" Value="Center" />
        </Style>

        <Style TargetType="Button">
            <Setter Property="Text" Value="LEARN MORE" />
            <Setter Property="FontSize" Value="Large" />
            <Setter Property="TextColor" Value="White" />
            <Setter Property="BackgroundColor" Value="Green" />
            <Setter Property="BorderRadius" Value="20" />
        </Style>
    </ContentPage.Resources>

    <ScrollView Orientation="Both">
        <FlexLayout>
            <Frame WidthRequest="300"
                   HeightRequest="480">

                <FlexLayout Direction="Column">
                    <Label Text="Seated Monkey"
                           Style="{StaticResource headerLabel}" />
                    <Label Text="This monkey is laid back and relaxed, and likes to watch the world go by." />
                    <Label Text="  &#x2022; Doesn't make a lot of noise" />
                    <Label Text="  &#x2022; Often smiles mysteriously" />
                    <Label Text="  &#x2022; Sleeps sitting up" />
                    <Image Source="{local:ImageResource FlexLayoutDemos.Images.SeatedMonkey.jpg}"
                           WidthRequest="180"
                           HeightRequest="180" />
                    <Label FlexLayout.Grow="1" />
                    <Button />
                </FlexLayout>
            </Frame>

            <Frame WidthRequest="300"
                   HeightRequest="480">

                <FlexLayout Direction="Column">
                    <Label Text="Banana Monkey"
                           Style="{StaticResource headerLabel}" />
                    <Label Text="Watch this monkey eat a giant banana." />
                    <Label Text="  &#x2022; More fun than a barrel of monkeys" />
                    <Label Text="  &#x2022; Banana not included" />
                    <Image Source="{local:ImageResource FlexLayoutDemos.Images.Banana.jpg}"
                           WidthRequest="240"
                           HeightRequest="180" />
                    <Label FlexLayout.Grow="1" />
                    <Button />
                </FlexLayout>
            </Frame>

            <Frame WidthRequest="300"
                   HeightRequest="480">

                <FlexLayout Direction="Column">
                    <Label Text="Face-Palm Monkey"
                           Style="{StaticResource headerLabel}" />
                    <Label Text="This monkey reacts appropriately to ridiculous assertions and actions." />
                    <Label Text="  &#x2022; Cynical but not unfriendly" />
                    <Label Text="  &#x2022; Seven varieties of grimaces" />
                    <Label Text="  &#x2022; Doesn't laugh at your jokes" />
                    <Image Source="{local:ImageResource FlexLayoutDemos.Images.FacePalm.jpg}"
                           WidthRequest="180"
                           HeightRequest="180" />
                    <Label FlexLayout.Grow="1" />
                    <Button />
                </FlexLayout>
            </Frame>
        </FlexLayout>
    </ScrollView>
</ContentPage>

Image 的隐式样式包括 Flexlayout 两个附加的可绑定属性的设置:

<Style TargetType="Image">
    <Setter Property="FlexLayout.Order" Value="-1" />
    <Setter Property="FlexLayout.AlignSelf" Value="Center" />
</Style>

Order 设置 –1 会导致 Image 元素首先显示在每个嵌套的 FlexLayout 视图中,而不考虑其在子集合中的位置。 CenterAlignSelf 属性会导致 ImageFlexLayout 内居中。 这将替代 AlignItems 属性的设置,默认值为 Stretch,意味着 LabelButton 子元素拉伸到 FlexLayout 的全宽。

在三个 FlexLayout 视图的每个视图中,一个空白 Label 位于 Button 前面,但它的 Grow 设置为 1。 这意味着,所有额外的垂直空间都分配给此空白 Label,从而有效地将 Button 推送到底部。

可绑定属性的详细信息

现在,你已经知道了 FlexLayout 一些常见的应用,接下可以更详细地探索 FlexLayout 的属性。 FlexLayout 定义在代码或 XAML 中 FlexLayout 本身上设置的六个可绑定属性,以控制方向和对齐方式。 (本文未介绍其中一个属性:Position。)

你可以使用示例的“试验”页面来试验剩余的可绑定属性。 通过此页面,可以从 FlexLayout 添加或删除子元素,并设置五个可绑定属性的组合。 FlexLayout 的所有子元素都是不同颜色和大小的 Label 视图,Text 属性设置为与其在 Children 集合中的位置对应的数字。

当程序启动时,五个 Picker 视图显示这五个 FlexLayout 属性的默认值。 屏幕底部的 FlexLayout 包含三个子元素:

“试验”页面:默认值

每个 Label 视图都有一个灰色背景,显示分配给 FlexLayout 内该 Label 的空间。 FlexLayout 本身的背景是 Alice Blue。 它占据页面的整个底部区域,左侧和右侧还有一点边距。

Direction 属性

Direction 属性的类型为 FlexDirection,是一个具有四个成员的枚举:

  • Column
  • ColumnReverse(或 XAML 中的 "column-reverse")
  • Row(默认值)
  • RowReverse(或 XAML 中的 "row-reverse")

在 XAML 中,可以使用小写、大写或混合大小写的枚举成员名称指定此属性的值,也可以使用括号中显示的两个额外的字符串,这些字符串与 CSS 指示符相同。 (在 XAML 分析器使用的 FlexDirectionTypeConverter 类中定义 "column-reverse" 和 "row-reverse" 字符串。)

下面是显示(从左到右)、Row 方向、Column 方向和 ColumnReverse 方向的 试验 页:

“试验”页面:方向

请注意,对于 Reverse 选项,项从右侧或底部开始。

Wrap 属性

Wrap 属性的类型为 FlexWrap,是一个具有三个成员的枚举:

  • NoWrap(默认值)
  • Wrap
  • Reverse(或 XAML 中的 "wrap-reverse")

从左到右,这些屏幕显示 12 个子元素的 NoWrapWrapReverse 选项:

“试验”页面:包装

Wrap 属性设置为 NoWrap 并且主轴受到约束(如此程序所示),并且主轴宽度或高到足以容纳所有子元素时,FlexLayout 会尝试使项更小,如 iOS 屏幕截图所示。 可以使用 Shrink 附加的可绑定属性控制项的收缩。

JustifyContent 属性

JustifyContent 属性的类型为 FlexJustify,是一个具有六个成员的枚举:

  • Start(或 XAML 中的 "flex-start"),默认值
  • Center
  • End(或 XAML 中的 "flex-end")
  • SpaceBetween(或 XAML 中的 "space-between")
  • SpaceAround(或 XAML 中的 "space-around")
  • SpaceEvenly

此属性指定在主轴上分隔项的方式,在本示例中是水平轴:

“试验”页面:证明内容合理

在这三个屏幕截图中,Wrap 属性设置为 WrapStart 默认值显示在之前的 Android 屏幕截图中。 此处的 iOS 屏幕截图显示了 Center 选项:所有项都移动到中心。 以字 Space 开头的三个选项分配项未占用的额外空间。 SpaceBetween 在项之间分配相等的空间;SpaceAround 在每个项周围放置相等的空间,而 SpaceEvenly 在每个项之间以及行上第一项之前和最后一项之后放置相等的空间。

AlignItems 属性

AlignItems 属性的类型为 FlexAlignItems,是一个具有四个成员的枚举:

  • Stretch(默认值)
  • Center
  • Start(或 XAML 中的 "flex-start")
  • End(或 XAML 中的 "flex-end")

这是两个属性之一(另一个是 AlignContent),指示子元素如何在十字轴上对齐。 在每个行中,子元素将拉伸(如上一屏幕截图所示),或在每个项的开始、中心或末尾对齐,如以下三个屏幕截图所示:

“试验”页面:将各项对齐

在 iOS 屏幕截图中,所有子元素的顶部都对齐。 在 Android 屏幕截图中,项目垂直居中,以最高的子元素为基础。 在 UWP 屏幕截图中,所有项的底部都对齐。

对于任何单个项,可以使用附加的可绑定属性 AlignSelf 替代 AlignItems 设置。

AlignContent 属性

AlignContent 属性的类型为 FlexAlignContent,是一个具有七个成员的枚举:

  • Stretch(默认值)
  • Center
  • Start(或 XAML 中的 "flex-start")
  • End(或 XAML 中的 "flex-end")
  • SpaceBetween(或 XAML 中的 "space-between")
  • SpaceAround(或 XAML 中的 "space-around")
  • SpaceEvenly

AlignItems一样,AlignContent 属性也会对齐十字轴上的子元素,但会影响整个行或列:

“试验”页面:对齐内容

在 iOS 屏幕截图中,两行都位于顶部;在 Android 屏幕截图中,它们位于中心;在 UWP 屏幕截图中位于底部。 也可用多种方式分隔行:

“试验”页面:对齐内容 2

当只有一行或一列时,AlignContent 不起作用。

附加的可绑定属性的详细信息

FlexLayout 定义五个附加的可绑定属性。 这些属性在 FlexLayout 的子元素上设置,仅与该特定子元素相关。

AlignSelf 属性

AlignSelf 附加的可绑定属性的类型为 FlexAlignSelf,是一个具有五个成员的枚举:

  • Auto(默认值)
  • Stretch
  • Center
  • Start(或 XAML 中的 "flex-start")
  • End(或 XAML 中的 "flex-end")

对于 FlexLayout 的任何单个子元素,此属性设置将替代 FlexLayout 本身上设置的 AlignItems 属性。 Auto 的默认设置是指使用 AlignItems 设置。

对于名为 label(或示例)的 Label 元素,可以在代码中设置 AlignSelf 属性,如下所示:

FlexLayout.SetAlignSelf(label, FlexAlignSelf.Center);

请注意,没有引用 LabelFlexLayout 父级。 在 XAML 中,设置如下属性:

<Label ... FlexLayout.AlignSelf="Center" ... />

Order 属性

Order 属性为 int 类型。 默认值为 0。

使用 Order 属性可以更改 FlexLayout 子元素的排列顺序。 通常,FlexLayout 子元素的排列顺序与 Children 集合中显示的顺序相同。 可以通过在一个或多个子元素上将 Order 附加的可绑定属性设置为非零整数值来替代此顺序。 然后,FlexLayout 根据每个子元素的 Order 属性设置来排列其子元素,但具有相同 Order 设置的子元素按它们在 Children 集合中显示的顺序排列。

Basis 属性

Basis 附加的可绑定属性指示分配给主轴上 FlexLayout 子元素的空间量。 由 Basis 属性指定的大小是父级 FlexLayout 的主轴上的大小。 因此,Basis 指示子元素的宽度(当子元素按行排列时)或高度(当子元素按列排列时)。

Basis 属性的类型为 FlexBasis,是一种结构。 可以用与设备无关的单位指定大小,也可以指定为 FlexLayout 大小的百分比。 Basis 属性的默认值是静态属性 FlexBasis.Auto,这意味着使用了子元素请求的宽度或高度。

在代码中,可以将名为 labelLabelBasis 属性设置为 40 个独立于设备的单元,如下所示:

FlexLayout.SetBasis(label, new FlexBasis(40, false));

FlexBasis 构造函数的第二个参数以 isRelative 命名,并指示大小是相对 (true) 还是绝对 (false)。 该参数的默认值为 false,因此也可以使用以下代码:

FlexLayout.SetBasis(label, new FlexBasis(40));

定义了从 floatFlexBasis 的隐式转换,因此可以进一步简化它:

FlexLayout.SetBasis(label, 40);

可以将 FlexLayout 父级的大小设置为 25%,如下所示:

FlexLayout.SetBasis(label, new FlexBasis(0.25f, true));

此小数部分值必须介于 0 到 1 的范围内。

在 XAML 中,可以使用设备无关单位以数字表示大小:

<Label ... FlexLayout.Basis="40" ... />

或者,可以在 0% 到 100% 的范围内指定百分比:

<Label ... FlexLayout.Basis="25%" ... />

示例的“基础试验”页面让你能够试验 Basis 属性。 该页显示五个具有交替背景和前景颜色的五个 Label 元素的包装列。 使用两个 Slider 元素可为第二和第四个 Label 指定 Basis 值:

“基础试验”页面

左侧的 iOS 屏幕截图以与设备无关的单位显示了两个 Label 元素的高度。 Android 屏幕以 FlexLayout 总高度的比例显示这些高度。 如果 Basis 设置为 100%,则子元素的高度为 FlexLayout,将换行到下一列并占据该列的整个高度,如 UWP 屏幕截图所示:看起来这五个子元素排列在一行中,但实际上按五列排列的。

Grow 属性

Grow 附加的可绑定属性的类型为 int。 默认值为 0,该值必须大于或等于 0。

Wrap 属性设置为 NoWrap 并且子元素行的总宽度小于 FlexLayout 的宽度,或者子元素的列比 FlexLayout 短时,Grow 属性将发挥作用。 Grow 属性指示如何在子项之间分配剩余空间。

增长试验页中,五个交替颜色的 Label 元素排列在一列中,两个 Slider 元素允许调整第二个和第四个 LabelGrow 属性。 最左侧的 iOS 屏幕截图显示默认 Grow 属性 0:

“扩大试验”页面

如果向任何一个子元素提供正 Grow 值,则该子元素将占用所有剩余空间,如 Android 屏幕截图所示。 还可以在两个或以上的个子元素之间分配此空间。 在 UWP 屏幕截图中,第二个 LabelGrow 属性设置为 0.5,而第四个 LabelGrow 属性为 1.5,第四个 Label 的剩余空间比第二个 Label 多三倍。

子视图使用该空间的方式取决于子元素的特定类型。 对于 Label,可以使用属性 HorizontalTextAlignmentVerticalTextAlignment 将文本放置在 Label 的总空间中。

Shrink 属性

Shrink 附加的可绑定属性的类型为 int。 默认值为 1,该值必须大于或等于 0。

Wrap 属性设置为 NoWrap 且子元素的聚合宽度大于 FlexLayout 的宽度时,或者单个子元素列的聚合高度大于 FlexLayout 的高度时,Shrink 属性将发挥作用。 通常,FlexLayout 会通过限制这些子项的大小以显示它们。 Shrink 属性可以指示哪些子项可优先按其完整大小显示。

收缩试验页创建了一个 FlexLayout,其中包含一行五个 Label 子元素,所需空间超过 FlexLayout 宽度。 左侧的 iOS 屏幕截图显示默认值为 1 的所有 Label 元素:

“缩小试验”页面

在 Android 屏幕截图中,第二个 LabelShrink 值设置为 0,而 Label 以全宽显示。 此外,第四个 Label 的值为大于 1 的 Shrink 值,但已收缩。 UWP 屏幕截图显示两个 Label 元素都给定了 Shrink 值 0,以允许它们以其完整大小显示(如果可能)。

可以同时设置 Grow 值和 Shrink 值,以适应聚合子元素大小有时可能小于或大于 FlexLayout 大小的情况。

使用 FlexLayout 设置 CSS 样式

可以使用与 FlexLayout 相关的 Xamarin.Forms 3.0 引入的 CSS 样式功能。 示例的“CSS 目录项”页面复制了“目录项”页面的布局,但具有许多样式的 CSS 样式表:

“CSS 目录项”页面

原始 CatalogItemsPage.xaml 文件在其具有 15 个 Setter 对象的 Resources 部分中具有五个 Style 定义。 在 CssCatalogItemsPage.xaml 文件中,已减少到只有四个 Setter 对象的两个 Style 定义。 这些样式补充了 Xamarin.Forms CSS 样式设置功能当前不支持的属性的 CSS 样式表:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:FlexLayoutDemos"
             x:Class="FlexLayoutDemos.CssCatalogItemsPage"
             Title="CSS Catalog Items">
    <ContentPage.Resources>
        <StyleSheet Source="CatalogItemsStyles.css" />

        <Style TargetType="Frame">
            <Setter Property="BorderColor" Value="Blue" />
            <Setter Property="CornerRadius" Value="15" />
        </Style>

        <Style TargetType="Button">
            <Setter Property="Text" Value="LEARN MORE" />
            <Setter Property="BorderRadius" Value="20" />
        </Style>
    </ContentPage.Resources>

    <ScrollView Orientation="Both">
        <FlexLayout>
            <Frame>
                <FlexLayout Direction="Column">
                    <Label Text="Seated Monkey" StyleClass="header" />
                    <Label Text="This monkey is laid back and relaxed, and likes to watch the world go by." />
                    <Label Text="  &#x2022; Doesn't make a lot of noise" />
                    <Label Text="  &#x2022; Often smiles mysteriously" />
                    <Label Text="  &#x2022; Sleeps sitting up" />
                    <Image Source="{local:ImageResource FlexLayoutDemos.Images.SeatedMonkey.jpg}" />
                    <Label StyleClass="empty" />
                    <Button />
                </FlexLayout>
            </Frame>

            <Frame>
                <FlexLayout Direction="Column">
                    <Label Text="Banana Monkey" StyleClass="header" />
                    <Label Text="Watch this monkey eat a giant banana." />
                    <Label Text="  &#x2022; More fun than a barrel of monkeys" />
                    <Label Text="  &#x2022; Banana not included" />
                    <Image Source="{local:ImageResource FlexLayoutDemos.Images.Banana.jpg}" />
                    <Label StyleClass="empty" />
                    <Button />
                </FlexLayout>
            </Frame>

            <Frame>
                <FlexLayout Direction="Column">
                    <Label Text="Face-Palm Monkey" StyleClass="header" />
                    <Label Text="This monkey reacts appropriately to ridiculous assertions and actions." />
                    <Label Text="  &#x2022; Cynical but not unfriendly" />
                    <Label Text="  &#x2022; Seven varieties of grimaces" />
                    <Label Text="  &#x2022; Doesn't laugh at your jokes" />
                    <Image Source="{local:ImageResource FlexLayoutDemos.Images.FacePalm.jpg}" />
                    <Label StyleClass="empty" />
                    <Button />
                </FlexLayout>
            </Frame>
        </FlexLayout>
    </ScrollView>
</ContentPage>

CSS 样式表在 Resources 部分的第一行中引用:

<StyleSheet Source="CatalogItemsStyles.css" />

另请注意,在这三个项中,每个项的两个元素包括 StyleClass 设置:

<Label Text="Seated Monkey" StyleClass="header" />
···
<Label StyleClass="empty" />

这些引用 CatalogItemsStyles.css 样式表中的选择器:

frame {
    width: 300;
    height: 480;
    background-color: lightyellow;
    margin: 10;
}

label {
    margin: 4 0;
}

label.header {
    margin: 8 0;
    font-size: large;
    color: blue;
}

label.empty {
    flex-grow: 1;
}

image {
    height: 180;
    order: -1;
    align-self: center;
}

button {
    font-size: large;
    color: white;
    background-color: green;
}

此处引用了几个 FlexLayout 附加的可绑定属性。 在 label.empty 选择器中,你将看到 flex-grow 属性,该属性设置空 Label 样式,以在 Button 上方提供一些空白空间。 image 选择器包含 order 属性和 align-self 属性,这两个属性都对应于 FlexLayout 附加的可绑定属性。

你已经了解,可以直接在 FlexLayout 上设置属性,并且可以在 FlexLayout 的子元素上设置附加的可绑定属性。 或者,可以使用传统的基于 XAML 的样式或 CSS 样式间接设置这些属性。 重要的是了解这些属性。 正是这些属性让 FlexLayout 真正变得灵活。

包含 Xamarin.University 的 FlexLayout

Xamarin.Forms 3.0 弹性布局视频