Friday 29 June 2018

Xamarin StackLayout Options

The stacklayout container is fairly straight forward however it does have some interesting behavior when it comes to vertical vs horizontal orientation.

default vertical behavior 


<?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="pav.LayoutsExample.StackLayoutPage">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="One" BackgroundColor="Yellow"/>
            <Label Text="two" BackgroundColor="Orange"/>
            <Label Text="three" BackgroundColor="Red" />
            <Label Text="four" BackgroundColor="Green"/>
            <Label Text="five" BackgroundColor="Blue"/>
            <Label Text="six" BackgroundColor="Brown"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

The above is the standard stack layout definition, it defaults to vertically stacking all of it's elements, each element fills its horizontal space, and takes up the minimum amount of vertical space, you could think of it as prioritizing vertical space.

vertical options for vertical orientation

<?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="pav.LayoutsExample.StackLayoutPage">
    <ContentPage.Content>
        <StackLayout Orientation="Vertical">
            <Label Text="start" BackgroundColor="Yellow"
                   VerticalOptions="Start"/>
            <Label Text="start &amp; expand" BackgroundColor="Orange"
                   VerticalOptions="StartAndExpand"/>
           
            <Label Text="center" BackgroundColor="Pink"
                   VerticalOptions="Center"/>
            <Label Text="center &amp; expand" BackgroundColor="Red"
                   VerticalOptions="CenterAndExpand"/>
           
            <Label Text="end" BackgroundColor="Aqua"
                   VerticalOptions="End"/>
            <Label Text="end &amp; expand" BackgroundColor="Green"
                   VerticalOptions="EndAndExpand"/>

            <Label Text="fill" BackgroundColor="Coral"
                   VerticalOptions="Fill"/>
            <Label Text="fill &amp; expand" BackgroundColor="LightBlue"
                   VerticalOptions="FillAndExpand"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

The above sets vertical options for all of the elements within the vertically oriented stacklayout container, notice that the elements that contain "xxxAndExpand" divide up any excess vertical space among themselves equally and then with the prefix either position themselves vertically at the start, in the middle, or at the end of that excess space. with the exception of the "FillAndExpand" label who simply fills up all of the vertical space allotted.

horizontal options for Vertical orientation

<?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="pav.LayoutsExample.StackLayoutPage">
    <ContentPage.Content>
        <StackLayout Orientation="Vertical">
            <Label Text="start" BackgroundColor="Yellow"
                   HorizontalOptions="Start"/>
            <Label Text="start &amp; expand" BackgroundColor="Orange"
                   HorizontalOptions="StartAndExpand"/>

            <Label Text="center" BackgroundColor="Pink"
                   HorizontalOptions="Center"/>
            <Label Text="center &amp; expand" BackgroundColor="Red"
                   HorizontalOptions="CenterAndExpand"/>

            <Label Text="end" BackgroundColor="Aqua"
                   HorizontalOptions="End"/>
            <Label Text="end &amp; expand" BackgroundColor="Green"
                   HorizontalOptions="EndAndExpand"/>

            <Label Text="fill" BackgroundColor="AliceBlue"
                   HorizontalOptions="Fill"/>
            <Label Text="fill &amp; expand" BackgroundColor="LightBlue"
                   HorizontalOptions="FillAndExpand"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

In the above we replaced the vertical options for horizontal once and notice that none of the "xxxAndFill" options really do much of anything, this is because the fill only affects it's orientation that is VerticalOptions affect the fill of Vertical StackLayouts and HorizontalOptions affect Horizontal Stacklayouts.

Also notice that by setting horizontal options our Vertical StackLayout no longer fills all of the horizontal space of our elements except where specified. and because doesn't covet horizontal space horizontal "Fill" is the same as "FillAndExpand".


horizontal and vertical options for Vertical orientation 

<?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="pav.LayoutsExample.StackLayoutPage">
    <ContentPage.Content>
        <StackLayout Orientation="Vertical">
            <Label Text="start" BackgroundColor="Yellow"
                   VerticalOptions="Start"
                   HorizontalOptions="Start"/>
            <Label Text="start &amp; expand" BackgroundColor="Orange"
                   VerticalOptions="StartAndExpand"
                   HorizontalOptions="StartAndExpand"/>

            <Label Text="center" BackgroundColor="Pink"
                   VerticalOptions="Center"
                   HorizontalOptions="Center"/>
            <Label Text="center &amp; expand" BackgroundColor="Red"
                   VerticalOptions="CenterAndExpand"
                   HorizontalOptions="CenterAndExpand"/>

            <Label Text="end" BackgroundColor="Aqua"
                   VerticalOptions="End"
                   HorizontalOptions="End"/>
            <Label Text="end &amp; expand" BackgroundColor="Green"
                   VerticalOptions="EndAndExpand"
                   HorizontalOptions="EndAndExpand"/>

            <Label Text="fill" BackgroundColor="AliceBlue"
                   VerticalOptions="Fill"
                   HorizontalOptions="Fill"/>
            <Label Text="fill &amp; expand" BackgroundColor="LightBlue"
                   VerticalOptions="FillAndExpand"
                   HorizontalOptions="FillAndExpand"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

In the above we apply both the horizontal and vertical options, notice that this time we get the same vertical expansion behavior that we expect, in which the elements that have a vertical option of "xxxAndExpand" divvy up the excess vertical space and then position themselves either at the start, middle or end of that excess space.

The horizontal options remove the default behavior of horizontal fill and position themselves at the start center or end in their horizontal space and again if they are marked to fill they fill the space, though since that's the default behavior we could have just as easily exluded horizontal options for the last two labels and the result would have been the same.


default horizontal behavior 

<?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="pav.LayoutsExample.StackLayoutPage">
    <ContentPage.Content>
        <StackLayout Orientation="Horizontal">
            <Label Text="One" BackgroundColor="Yellow"/>
            <Label Text="two" BackgroundColor="Orange"/>
            <Label Text="three" BackgroundColor="Red" />
            <Label Text="four" BackgroundColor="Green"/>
            <Label Text="five" BackgroundColor="Blue"/>
            <Label Text="six" BackgroundColor="Brown"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

The above simply changes the stacklayout's orientation to vertical which prioritizes horizontal space, notice that the elements now fill the vertical space, but take up the minimal horizontal space.

horizontal options for horizontal orientation

<?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="pav.LayoutsExample.StackLayoutPage">
    <ContentPage.Content>
        <StackLayout Orientation="Horisontal">
            <Label Text="start" BackgroundColor="Yellow"
                   HorizontalOptions="Start"/>
            <Label Text="start &amp; expand" BackgroundColor="Orange"
                   HorizontalOptions="StartAndExpand"/>

            <Label Text="center" BackgroundColor="Pink"
                   HorizontalOptions="Center"/>
            <Label Text="center &amp; expand" BackgroundColor="Red"
                   HorizontalOptions="CenterAndExpand"/>

            <Label Text="end" BackgroundColor="Aqua"
                   HorizontalOptions="End"/>
            <Label Text="end &amp; expand" BackgroundColor="Green"
                   HorizontalOptions="EndAndExpand"/>

            <Label Text="fill" BackgroundColor="AliceBlue"
                   HorizontalOptions="Fill"/>
            <Label Text="fill &amp; expand" BackgroundColor="LightBlue"
                   HorizontalOptions="FillAndExpand"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

We can see that with our Horizontal options set instead of all of our elements contained within our horizontal StackLayout the ones that have their HorizontalOptions set to "xxxAndExpand" divvy up the excess horizontal space among themselves and position themselves in accordance to their request, start, center or end; with the exception of the FillAndExpand label which takes it's share of the excess space and fills it.


vertical options for Horizontal layout

<?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="pav.LayoutsExample.StackLayoutPage">
    <ContentPage.Content>
        <StackLayout Orientation="Horizontal">
            <Label Text="start" BackgroundColor="Yellow"
                   VerticalOptions="Start"/>
            <Label Text="start &amp; expand" BackgroundColor="Orange"
                   VerticalOptions="StartAndExpand"/>

            <Label Text="center" BackgroundColor="Pink"
                   VerticalOptions="Center"/>
            <Label Text="center &amp; expand" BackgroundColor="Red"
                   VerticalOptions="CenterAndExpand"/>

            <Label Text="end" BackgroundColor="Aqua"
                   VerticalOptions="End"/>
            <Label Text="end &amp; expand" BackgroundColor="Green"
                   VerticalOptions="EndAndExpand"/>

            <Label Text="fill" BackgroundColor="AliceBlue"
                   VerticalOptions="Fill"/>
            <Label Text="fill &amp; expand" BackgroundColor="LightBlue"
                   VerticalOptions="FillAndExpand"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

Now with only the vertical options specified, we see that the default vertical fill behavior of elements is overridden to start, center and end; and of course the default horizontal expansion property defaults to the normal horizontal StackLayout behavior of being conservative.


horizontal & vertical options for Horizontal layout

<?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="pav.LayoutsExample.StackLayoutPage">
    <ContentPage.Content>
        <StackLayout Orientation="Vertical">
            <Label Text="start" BackgroundColor="Yellow"
                   VerticalOptions="Start"
                   HorizontalOptions="Start"/>
            <Label Text="start &amp; expand" BackgroundColor="Orange"
                   VerticalOptions="StartAndExpand"
                   HorizontalOptions="StartAndExpand"/>

            <Label Text="center" BackgroundColor="Pink"
                   VerticalOptions="Center"
                   HorizontalOptions="Center"/>
            <Label Text="center &amp; expand" BackgroundColor="Red"
                   VerticalOptions="CenterAndExpand"
                   HorizontalOptions="CenterAndExpand"/>

            <Label Text="end" BackgroundColor="Aqua"
                   VerticalOptions="End"
                   HorizontalOptions="End"/>
            <Label Text="end &amp; expand" BackgroundColor="Green"
                   VerticalOptions="EndAndExpand"
                   HorizontalOptions="EndAndExpand"/>

            <Label Text="fill" BackgroundColor="AliceBlue"
                   VerticalOptions="Fill"
                   HorizontalOptions="Fill"/>
            <Label Text="fill &amp; expand" BackgroundColor="LightBlue"
                   VerticalOptions="FillAndExpand"
                   HorizontalOptions="FillAndExpand"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

When we set both vertical and horizontal options we see that the when the StackLayout's orientation is set to horizontal we see that the horizontal expand is applied at the same time as our vertical positioning


Summary


  • Vertical StackLayout by default gives each child the minimum amount of vertical space, but fills their horizontal space.
  • Horizontal StackLayout by default gives each child the minimum amount of horizontal space, but fills their vertical space.
  • The elements contained in a stack layout can influence the way they are rendered:
    • Start: will place the element at the very top or or to the very left
    • Center: will place the element either in the middle vertically or horizontally of it's space.
    • End: will place the element at the far right or bottom of the space the stacklayout provides
    • xxxAndExpand: if there is excess horizontal or vertical space all elements that use an "xxxAndExpand" option will divvy up that excess space equally and be placed at the start, center, or end of it.
    • Fill will take up all of the space allocated to the element by the stackpanel
    • FillAndExpand will expand the size of the element to fill all of it's allocated space including it's share of the excess space.