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 }
}
}
},
// ...
}
};
}
}






