Xamarin.Forms StackLayout

Download Sample Скачайте пример

Xamarin.Forms StackLayout

Дочерние StackLayout представления упорядочиваются в одномерном стеке по горизонтали или по вертикали. По умолчанию StackLayout имеет вертикальную ориентацию. Кроме того, StackLayout можно использовать в качестве родительского макета, содержащего другие дочерние макеты.

Класс StackLayout определяет следующие свойства:

  • OrientationStackOrientationТип , представляет направление, в котором размещаются дочерние представления. Значение по умолчанию этого свойства равно Vertical.
  • SpacingdoubleТип , указывает объем пространства между каждым дочерним представлением. Значение по умолчанию этого свойства — шесть единиц, независимых от устройства.

Эти свойства поддерживаются объектами, что означает, что свойства могут быть целевыми BindableProperty объектами привязки данных и стилем.

Класс StackLayout является производным от Layout<T> класса, который определяет Children свойство типа IList<T>. Свойство Children является ContentProperty классом Layout<T> , поэтому не требуется явно задавать из 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>

В этом примере создается вертикальная StackLayout содержащая Label и BoxView объекты. По умолчанию между дочерними представлениями существует шесть независимых от устройств единиц пространства:

Screenshot of a vertically oriented 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 }
            }
        };
    }
}

Примечание.

Значение Margin свойства представляет расстояние между элементом и его смежными элементами. Дополнительные сведения см. в статье Поля и заполнение.

Горизонтальная ориентация

В следующем XAML показано, как создать горизонтально ориентированный StackLayout объект, задав для свойства значение OrientationHorizontal:

<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>

В этом примере создается горизонтальный StackLayout содержащий BoxView объекты с шестью независимыми от устройства единицами пространства между дочерними представлениями:

Screenshot of a horizontally oriented 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 }
        }
    };
}

Пространство между дочерними представлениями

Интервал между дочерними представлениями StackLayout можно изменить, задав Spacing свойству double значение:

<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>

В этом примере создается вертикальная StackLayout содержащая Label и BoxView объекты, не имеющие интервалов между ними:

Screenshot of a StackLayout without any spacing

Совет

Свойство 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 и свойств, а также значений их HorizontalOptions и VerticalOptionsWidthRequest свойств. В вертикальном StackLayoutпредставлении дочерние представления расширяются, чтобы заполнить доступную ширину, если их размер не задан явным образом. Аналогичным образом, в горизонтальном StackLayoutпредставлении дочерние представления расширяются, чтобы заполнить доступную высоту, если их размер не задан явным образом.

Свойства HorizontalOptions и VerticalOptions дочерние StackLayoutпредставления могут быть заданы в поля из LayoutOptions структуры, которые инкапсулируют два параметра макета:

  • Выравнивание определяет положение и размер дочернего представления в родительском макете.
  • Расширение указывает, следует ли дочернему представлению использовать дополнительное пространство, если оно доступно.

Совет

Не устанавливайте HorizontalOptions свойства и VerticalOptions свойства, StackLayout если вам не нужно. Значения по умолчанию для свойств 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объекта. Поля , и Fill поля используются для определения выравнивания Label объектов в родительском элементеStackLayout:StartCenterEnd

Screenshot of a StackLayout with alignment options set

StackLayout учитывает только параметры выравнивания дочерних представлениях, которые находятся в направлении, противоположном ориентации StackLayout. Поэтому дочерние представления Label в StackLayout с вертикальной ориентацией получают свойства HorizontalOptions в соответствии с одним из следующих полей выравнивания:

Эквивалентный код на 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 задаются параметры расширения для каждого Label из StackLayoutследующих элементов:

<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, и EndAndExpandCenterAndExpandFillAndExpand поля используются для определения предпочтений выравнивания и того, занимает ли Label больше места, если оно доступно в родительском элементе:StackLayout

Screenshot of a StackLayout with expansion options set

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 содержит вложенные StackLayout объекты внутри Frame объектов. Родительский объект StackLayout ориентирован по вертикали, а дочерние StackLayout объекты ориентированы по горизонтали:

Screenshot of nested StackLayout objects

Внимание

Чем глубже вы вложены 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 }
                        }
                    }
                },
                // ...
            }
        };
    }
}