Xamarin.Forms StackLayout
StackLayout
在水平或垂直方向在一维堆栈中组织子视图。 默认情况下,StackLayout
是垂直方向。 此外,StackLayout
还可用作包含其他子布局的父布局。
StackLayout
类定义以下属性:
StackOrientation
类型 的Orientation
表示子视图的排列方向。 此属性的默认值为Vertical
。double
类型的Spacing
指示每个子视图之间的空间量。 此属性的默认值为六个与设备无关的单位。
这些属性由 BindableProperty
对象提供支持,这意味着它们可以作为数据绑定的目标,也可以进行设置样式。
StackLayout
类派生自 Layout<T>
类,后者定义了类型 IList<T>
的 Children
属性。 由于 Children
属性是 Layout<T>
类的 ContentProperty
,因此不需要通过 XAML 显式设置。
提示
若要获取最佳可能布局性能,请遵循优化布局性能中的准则。
垂直方向
以下 XAML 展示如何创建包含不同子视图且方向垂直的 StackLayout
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StackLayoutDemos.Views.VerticalStackLayoutPage"
Title="Vertical StackLayout demo">
<StackLayout Margin="20">
<Label Text="Primary colors" />
<BoxView Color="Red" />
<BoxView Color="Yellow" />
<BoxView Color="Blue" />
<Label Text="Secondary colors" />
<BoxView Color="Green" />
<BoxView Color="Orange" />
<BoxView Color="Purple" />
</StackLayout>
</ContentPage>
此示例创建包含 Label
和 BoxView
对象的垂直 StackLayout
。 默认情况下,子视图之间有六个与设备无关的空间单位:
等效 C# 代码如下:
public class VerticalStackLayoutPageCS : ContentPage
{
public VerticalStackLayoutPageCS()
{
Title = "Vertical StackLayout demo";
Content = new StackLayout
{
Margin = new Thickness(20),
Children =
{
new Label { Text = "Primary colors" },
new BoxView { Color = Color.Red },
new BoxView { Color = Color.Yellow },
new BoxView { Color = Color.Blue },
new Label { Text = "Secondary colors" },
new BoxView { Color = Color.Green },
new BoxView { Color = Color.Orange },
new BoxView { Color = Color.Purple }
}
};
}
}
水平方向
以下 XAML 展示如何通过将 Orientation
属性设置为 Horizontal
创建水平方向的 StackLayout
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StackLayoutDemos.Views.HorizontalStackLayoutPage"
Title="Horizontal StackLayout demo">
<StackLayout Margin="20"
Orientation="Horizontal"
HorizontalOptions="Center">
<BoxView Color="Red" />
<BoxView Color="Yellow" />
<BoxView Color="Blue" />
<BoxView Color="Green" />
<BoxView Color="Orange" />
<BoxView Color="Purple" />
</StackLayout>
</ContentPage>
此示例创建一个包含 BoxView
对象的水平 StackLayout
,且子视图之间有六个与设备无关的空间单位:
等效 C# 代码如下:
public HorizontalStackLayoutPageCS()
{
Title = "Horizontal StackLayout demo";
Content = new StackLayout
{
Margin = new Thickness(20),
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.Center,
Children =
{
new BoxView { Color = Color.Red },
new BoxView { Color = Color.Yellow },
new BoxView { Color = Color.Blue },
new BoxView { Color = Color.Green },
new BoxView { Color = Color.Orange },
new BoxView { Color = Color.Purple }
}
};
}
子视图之间的间距
可以通过将 Spacing
属性设置为 double
值更改 StackLayout
中子视图之间的间距:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StackLayoutDemos.Views.StackLayoutSpacingPage"
Title="StackLayout Spacing demo">
<StackLayout Margin="20"
Spacing="0">
<Label Text="Primary colors" />
<BoxView Color="Red" />
<BoxView Color="Yellow" />
<BoxView Color="Blue" />
<Label Text="Secondary colors" />
<BoxView Color="Green" />
<BoxView Color="Orange" />
<BoxView Color="Purple" />
</StackLayout>
</ContentPage>
此示例创建一个包含 Label
和 BoxView
对象的垂直 StackLayout
,且这些对象之间没有间距:
提示
可将 Spacing
属性设置为负值,以使子视图重叠。
等效 C# 代码如下:
public class StackLayoutSpacingPageCS : ContentPage
{
public StackLayoutSpacingPageCS()
{
Title = "StackLayout Spacing demo";
Content = new StackLayout
{
Margin = new Thickness(20),
Spacing = 0,
Children =
{
new Label { Text = "Primary colors" },
new BoxView { Color = Color.Red },
new BoxView { Color = Color.Yellow },
new BoxView { Color = Color.Blue },
new Label { Text = "Secondary colors" },
new BoxView { Color = Color.Green },
new BoxView { Color = Color.Orange },
new BoxView { Color = Color.Purple }
}
};
}
}
子视图的位置和大小
StackLayout
中子视图的大小和位置取决于子视图的 HeightRequest
和 WidthRequest
属性的值,以及其 HorizontalOptions
和 VerticalOptions
属性的值。 在垂直 StackLayout
中,如果未显式设置子视图的大小,则可以将其展开以填充可用宽度。 同样,在水平 StackLayout
中,如果未显式设置子视图的大小,则可将其展开以填充可用高度。
可以将 StackLayout
及其子视图的 HorizontalOptions
和 VerticalOptions
属性设置为来自 LayoutOptions
结构的字段,该结构封装了两个布局首选项:
- 对齐方式决定了子视图在其父布局中的位置和大小。
- 扩展指示子视图是否应使用额外空间(如果可用)。
提示
除非需要,否则不要设置 StackLayout
的 HorizontalOptions
和 VerticalOptions
属性。 LayoutOptions.Fill
和 LayoutOptions.FillAndExpand
的默认值可以实现最佳布局优化。 更改这些属性会产生成本并消耗内存,即使是将它们设置回默认值。
对齐
以下 XAML 示例在 StackLayout
中对每个子视图设置对齐方式首选项:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StackLayoutDemos.Views.AlignmentPage"
Title="Alignment demo">
<StackLayout Margin="20">
<Label Text="Start"
BackgroundColor="Gray"
HorizontalOptions="Start" />
<Label Text="Center"
BackgroundColor="Gray"
HorizontalOptions="Center" />
<Label Text="End"
BackgroundColor="Gray"
HorizontalOptions="End" />
<Label Text="Fill"
BackgroundColor="Gray"
HorizontalOptions="Fill" />
</StackLayout>
</ContentPage>
在此示例中,对 Label
对象设置对齐方式首选项,以控制其在 StackLayout
中的位置。 Start
、Center
、End
和 Fill
字段用于定义 Label
对象在父 StackLayout
中的对齐方式:
StackLayout
仅遵循与 StackLayout
方向相反的子视图的对齐方式首选项。 因此,垂直方向的 StackLayout
中的 Label
子视图将其 HorizontalOptions
属性设置为对齐方式字段中的其中一种:
Start
,将Label
置于StackLayout
的左侧。Center
,它将Label
置于StackLayout
中心。End
,将Label
置于StackLayout
的右侧。Fill
,确保Label
填充到StackLayout
的宽度。
等效 C# 代码如下:
public class AlignmentPageCS : ContentPage
{
public AlignmentPageCS()
{
Title = "Alignment demo";
Content = new StackLayout
{
Margin = new Thickness(20),
Children =
{
new Label { Text = "Start", BackgroundColor = Color.Gray, HorizontalOptions = LayoutOptions.Start },
new Label { Text = "Center", BackgroundColor = Color.Gray, HorizontalOptions = LayoutOptions.Center },
new Label { Text = "End", BackgroundColor = Color.Gray, HorizontalOptions = LayoutOptions.End },
new Label { Text = "Fill", BackgroundColor = Color.Gray, HorizontalOptions = LayoutOptions.Fill }
}
};
}
}
扩展
以下 XAML 示例在 StackLayout
中的每个 Label
上设置扩展首选项:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StackLayoutDemos.Views.ExpansionPage"
Title="Expansion demo">
<StackLayout Margin="20">
<BoxView BackgroundColor="Red"
HeightRequest="1" />
<Label Text="Start"
BackgroundColor="Gray"
VerticalOptions="StartAndExpand" />
<BoxView BackgroundColor="Red"
HeightRequest="1" />
<Label Text="Center"
BackgroundColor="Gray"
VerticalOptions="CenterAndExpand" />
<BoxView BackgroundColor="Red"
HeightRequest="1" />
<Label Text="End"
BackgroundColor="Gray"
VerticalOptions="EndAndExpand" />
<BoxView BackgroundColor="Red"
HeightRequest="1" />
<Label Text="Fill"
BackgroundColor="Gray"
VerticalOptions="FillAndExpand" />
<BoxView BackgroundColor="Red"
HeightRequest="1" />
</StackLayout>
</ContentPage>
在此示例中,在 Label
对象上设置了扩展首选项以控制它们在 StackLayout
中的大小。 StartAndExpand
、CenterAndExpand
、EndAndExpand
和 FillAndExpand
字段用于定义对齐方式首选项,以及如果父级 StackLayout
内有更多空间可用,Label
是否将占用更多空间:
StackLayout
只能按照其方向展开子视图。 因此,垂直方向的 StackLayout
可以扩展 Label
子视图,该视图将 VerticalOptions
属性设置为其中一个扩展字段。 这意味着,对于垂直对齐方式,每个 Label
在 StackLayout
内占据相同的空间量。 但是,只有最后一个 Label
(可将 VerticalOptions
属性设置为 FillAndExpand
)具有不同的大小。
提示
使用 StackLayout
时,请确保只有一个子视图设置为 LayoutOptions.Expands
。 此属性可确保指定子级会占用 StackLayout
可以向它提供的最大空间,而多次执行这些计算比较浪费。
等效 C# 代码如下:
public ExpansionPageCS()
{
Title = "Expansion demo";
Content = new StackLayout
{
Margin = new Thickness(20),
Children =
{
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 },
new Label { Text = "StartAndExpand", BackgroundColor = Color.Gray, VerticalOptions = LayoutOptions.StartAndExpand },
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 },
new Label { Text = "CenterAndExpand", BackgroundColor = Color.Gray, VerticalOptions = LayoutOptions.CenterAndExpand },
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 },
new Label { Text = "EndAndExpand", BackgroundColor = Color.Gray, VerticalOptions = LayoutOptions.EndAndExpand },
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 },
new Label { Text = "FillAndExpand", BackgroundColor = Color.Gray, VerticalOptions = LayoutOptions.FillAndExpand },
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 }
}
};
}
重要
使用 StackLayout
中的所有空间时,扩展首选项不起作用。
有关对齐方式和扩展的详细信息,请参阅 Xamarin.Forms 中的布局选项。
嵌套的 StackLayout 对象
StackLayout
可用作包含嵌套子 StackLayout
对象或其他子布局的父布局。
以下 XAML 展示了一个嵌套 StackLayout
对象的示例:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StackLayoutDemos.Views.CombinedStackLayoutPage"
Title="Combined StackLayouts demo">
<StackLayout Margin="20">
...
<Frame BorderColor="Black"
Padding="5">
<StackLayout Orientation="Horizontal"
Spacing="15">
<BoxView Color="Red" />
<Label Text="Red"
FontSize="Large"
VerticalOptions="Center" />
</StackLayout>
</Frame>
<Frame BorderColor="Black"
Padding="5">
<StackLayout Orientation="Horizontal"
Spacing="15">
<BoxView Color="Yellow" />
<Label Text="Yellow"
FontSize="Large"
VerticalOptions="Center" />
</StackLayout>
</Frame>
<Frame BorderColor="Black"
Padding="5">
<StackLayout Orientation="Horizontal"
Spacing="15">
<BoxView Color="Blue" />
<Label Text="Blue"
FontSize="Large"
VerticalOptions="Center" />
</StackLayout>
</Frame>
...
</StackLayout>
</ContentPage>
在此示例中,父级 StackLayout
包含 Frame
对象中嵌套的 StackLayout
对象。 父级 StackLayout
是垂直朝向,而子级 StackLayout
对象是水平朝向:
重要
嵌套 StackLayout
对象和其他布局越深,嵌套布局对性能的影响就越大。 有关详细信息,请参阅选择正确的布局。
等效 C# 代码如下:
public class CombinedStackLayoutPageCS : ContentPage
{
public CombinedStackLayoutPageCS()
{
Title = "Combined StackLayouts demo";
Content = new StackLayout
{
Margin = new Thickness(20),
Children =
{
new Label { Text = "Primary colors" },
new Frame
{
BorderColor = Color.Black,
Padding = new Thickness(5),
Content = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Spacing = 15,
Children =
{
new BoxView { Color = Color.Red },
new Label { Text = "Red", FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)), VerticalOptions = LayoutOptions.Center }
}
}
},
new Frame
{
BorderColor = Color.Black,
Padding = new Thickness(5),
Content = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Spacing = 15,
Children =
{
new BoxView { Color = Color.Yellow },
new Label { Text = "Yellow", FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)), VerticalOptions = LayoutOptions.Center }
}
}
},
new Frame
{
BorderColor = Color.Black,
Padding = new Thickness(5),
Content = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Spacing = 15,
Children =
{
new BoxView { Color = Color.Blue },
new Label { Text = "Blue", FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)), VerticalOptions = LayoutOptions.Center }
}
}
},
// ...
}
};
}
}