Xamarin.Forms的LayoutOptions,特别是Fill和Expand有什么区别?

182
在 Xamarin.Forms 中,每个 View 都有两个属性: HorizontalOptionsVerticalOptions。它们都是 LayoutOptions 类型的,并且可以具有以下值:
  • LayoutOptions.Start
  • LayoutOptions.Center
  • LayoutOptions.End
  • LayoutOptions.Fill
  • LayoutOptions.StartAndExpand
  • LayoutOptions.CenterAndExpand
  • LayoutOptions.EndAndExpand
  • LayoutOptions.FillAndExpand
显然,它控制视图在父视图上的对齐方式。但每个选项的行为究竟如何?Fill 和后缀 Expand 的区别是什么?
3个回答

356

简短回答

StartCenterEndFill定义了视图在其空间内的对齐方式

Expand定义了是否占用更多空间(如果可用)。

理论

结构体LayoutOptions控制两个不同的行为:

  1. 对齐:视图如何在父视图内对齐?

    • Start:对于垂直对齐,视图向上移动。对于水平对齐,通常是左侧。(但请注意,在使用从右到左的语言设置的设备上,情况相反,即右对齐。)
    • Center:视图居中。
    • End:通常是底部或右对齐。(在从右到左的语言上,当然是左对齐。)
    • Fill:此对齐略有不同。视图将沿父视图的全部大小拉伸。

    但是,如果父视图不比其子视图大,您将不会注意到这些对齐方式之间的任何区别。对齐只对具有可用附加空间的父视图有影响。

  2. 扩展:元素是否会占用更多空间(如果可用)?

    • 后缀Expand:如果父视图大于所有子视图的组合大小,即有额外空间可用,则该空间在带有该后缀的子视图之间按比例分配。这些子视图将“占用”其空间,但不一定“填充”它。我们将在下面的示例中查看此行为。
    • 没有后缀:没有Expand后缀的子视图将不会获得额外的空间,即使有更多的空间可用。

    同样,如果父视图不比其子视图大,则扩展后缀也没有任何区别。

示例

让我们来看以下示例以了解所有八个布局选项之间的差异。

应用程序包含一个带有八个嵌套的白色按钮的深灰色StackLayout,每个按钮都带有其垂直布局选项的标签。单击其中一个按钮,将其垂直布局选项分配给堆栈布局。这样我们就可以轻松测试视图与具有不同布局选项的父视图之间的交互。

(代码的最后几行添加了额外的黄色框。稍后我们将回到这一点。)

public static class App
{
    static readonly StackLayout stackLayout = new StackLayout {
        BackgroundColor = Color.Gray,
        VerticalOptions = LayoutOptions.Start,
        Spacing = 2,
        Padding = 2,
    };

    public static Page GetMainPage()
    {
        AddButton("Start", LayoutOptions.Start);
        AddButton("Center", LayoutOptions.Center);
        AddButton("End", LayoutOptions.End);
        AddButton("Fill", LayoutOptions.Fill);
        AddButton("StartAndExpand", LayoutOptions.StartAndExpand);
        AddButton("CenterAndExpand", LayoutOptions.CenterAndExpand);
        AddButton("EndAndExpand", LayoutOptions.EndAndExpand);
        AddButton("FillAndExpand", LayoutOptions.FillAndExpand);

        return new NavigationPage(new ContentPage {
            Content = stackLayout,
        });
    }

    static void AddButton(string text, LayoutOptions verticalOptions)
    {
        stackLayout.Children.Add(new Button {
            Text = text,
            BackgroundColor = Color.White,
            VerticalOptions = verticalOptions,
            HeightRequest = 20,
            Command = new Command(() => {
                stackLayout.VerticalOptions = verticalOptions;
                (stackLayout.ParentView as Page).Title = "StackLayout: " + text;
            }),
        });
        stackLayout.Children.Add(new BoxView {
            HeightRequest = 1,
            Color = Color.Yellow,
        });
    }
}
下面的截图显示了单击每个八个按钮时的结果。我们得出以下观察结果:
- 只要父级stackLayout很紧凑(不填充整个页面),则每个Button的垂直布局选项可以忽略不计。 - 垂直布局选项只有在stackLayout更大(例如通过Fill对齐方式)且各个按钮具有Expand后缀时才有影响。 - 额外的空间均匀分配给带有Expand后缀的所有按钮。为了更清楚地看到这一点,我们在每两个相邻按钮之间添加了黄色水平线。 - 高度大于请求高度的按钮并不一定会“填充”它。在这种情况下,其实际行为由其对齐方式控制。例如,它们可以在空间的顶部、中心或底部对齐或完全填充它。 - 所有按钮跨越整个布局的宽度,因为我们只修改了VerticalOptions。 截图 在此处找到相应的高分辨率截图。

6
这个图像看起来像是中指表情,哈哈。开玩笑的,它真的很有帮助。 - Joy Rex
1
@JoyRex:也许这个版本会清晰一些;) - Falko
4
我对上面的输出结果感到困惑。start和startAndExpand都是相同的输出结果。它们之间有什么区别?如果可能的话,你能给出解释吗? - Ranjithkumar
1
99% 的情况下,你需要使用 FillAndExpand - Stephane Delcroix
2
@RanjithKumar 他们是一样的。如果StackLayout嵌套在另一个父级中,那么它的FillAndExpand可能会有所不同 - 它将在父级内扩展。 - Miha Markic
显示剩余3条评论

18

当前版本的Xamarin.Forms存在一些小问题,也许已经存在一段时间了。

CenterAndExpand通常不会扩展,绕过它可能会令人困惑。

例如,如果您有一个设置为CenterAndExpandStackLayout,然后在其中放置一个标签,该标签也设置为CenterAndExpand,您会期望标签是StackLayout的全宽度。但是没有。它不会扩展。您必须将StackLayout设置为"FillAndExpand"以使嵌套的标签对象扩展到StackLayout的全宽度,然后使用HorizontalTextAlignment="Center"告诉标签居中文本,而不是自身作为对象。根据我的经验,如果您真的想确保它可以扩展以适应大小,则需要将父元素和嵌套子元素都设置为FillAndExpand

        <StackLayout HorizontalOptions="FillAndExpand"
                     Orientation="Vertical"
                     WidthRequest="300">
            <Label BackgroundColor="{StaticResource TileAlerts}"
                   HorizontalOptions="FillAndExpand"
                   Style="{StaticResource LabelStyleReversedLrg}"
                   HorizontalTextAlignment="Center"
                   Text="Alerts" />

3
“你会期望标签的宽度与StackLayout一样宽。” 这种假设是不正确的。 Expand 仅用于 StackLayout 的子元素。因此,如果您的 StackLayout 是根元素或不在其他 StackLayout 中,则 Expand 没有任何影响。相反,除了 Fill 以外的任何选项都会作为“自适应内容”进行大小调整,这就是您看到的情况。 - therealjohn
此外,扩展仅适用于与 StackLayout 相同方向的 LayoutOptions。在本例中,布局为"垂直",但相关选项是水平的(相反)。 - therealjohn
1
术语“AndExpand”是有歧义的。它可以被解释为“尽可能扩展”或“仅扩展所需的量”。我认为微软应该将这些术语更改为一些不那么令人困惑的东西,比如“CenterAndExpandToParent”或“CenterAndExpandAsNeeded”。 - SendETHToThisAddress

2

Falko提供了很好的解释,但我想用另一种视觉方式来补充说明这些标记在xaml中的工作原理,这是我大多数时候喜欢使用的方式。我制作了一个简单的项目来测试显示结果。以下是Main Page的Xaml代码:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Alignments.MainPage"
             BackgroundColor="White">


    <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="LightGray" Padding="1" Margin="30">
        <Label Text="Vert: EndAndExpand, Horz: EndAndExpand" VerticalOptions="EndAndExpand" HorizontalOptions="EndAndExpand" BackgroundColor="White"/>
    </StackLayout>


</ContentPage>

如您所见,这是一个非常简单的StackLayout,其中包含一个Label。对于下面的每个图像,我保持了相同的StackLayout,只是更改了Entry的水平和垂直选项,并更改了文本以显示所选选项,因此您可以看到Entry如何移动和调整大小。
以下是用于Start的代码:

Start vs StartAndExpand

<Label Text="Vert: Start, Horz: Start" VerticalOptions="Start" HorizontalOptions="Start" BackgroundColor="White"/>

以下是用于 StartAndExpand 的代码:

<Label Text="Vert: StartAndExpand, Horz: StartAndExpand" VerticalOptions="StartAndExpand" HorizontalOptions="StartAndExpand" BackgroundColor="White"/>

如您所见,除了StartAndExpand选项使用了更多的文本之外,在视觉上没有任何区别。此内容已在我的三星A30物理设备上进行了测试。虽然这些可能在不同设备上显示不同,但我认为这里所有的图像集体展示了Xamarin中存在一些错误。其余部分我将仅展示截屏,我认为它们是自说明的。
图片链接:
https://istack.dev59.com/gtSBO.webp https://istack.dev59.com/GuOXT.webp https://istack.dev59.com/8whoq.webp 我还建议查看 Microsoft 文档以获得一些其他细节。值得注意的是,“扩展仅由 StackLayout 使用”。

1
不错的可视化效果。但我不明白为什么这应该显示Xamarin中的错误。可能会让人困惑的是,标签可以占用比它们的白色背景(我的示例中的灰色区域)更多的空间。因此,“Vert Center”标签在其所占用的空间内居中 - 而不是在整个页面内居中。显然,六年过去了,这个话题仍然像以前一样令人困惑。 - Falko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接