Friday 29 June 2018

Xamarin Grid Layout

The Grid container in Xamarin is a container that let's you arrange your controls in a two dimensional table by specifying rows, columns and there respective heights and widths. There are a couple of "magic" values for these heights and widths:

  • *: is a relative layout, it'll make the column or row take up a relative amount of space in comparison to the other rows or columns
  • Auto: will make the column or row the just big enough to fit the largest element
  • Value: will set a row or column to a numeric height or width.
Star Values 

<?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.GridLayoutExample.MainPage">

    <ContentPage.Resources>
        <Style TargetType="Label">
            <Setter Property="HorizontalTextAlignment" Value="Center"/>
            <Setter Property="VerticalTextAlignment" Value="Center" />
        </Style>
    </ContentPage.Resources>
   
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Label Text="top left"    BackgroundColor="Yellow"     Grid.Column="0" Grid.Row="0"/>
        <Label Text="top center"  BackgroundColor="Orange"     Grid.Column="1" Grid.Row="0"/>
        <Label Text="top right"   BackgroundColor="Red"        Grid.Column="2" Grid.Row="0"/>

        <Label Text="center left" BackgroundColor="LightGreen" Grid.Column="0" Grid.Row="1"/>
        <Label Text="center center" BackgroundColor="Aqua"     Grid.Column="1" Grid.Row="1"/>
        <Label Text="center right" BackgroundColor="Green"     Grid.Column="2" Grid.Row="1"/>

        <Label Text="bottom left" BackgroundColor="AliceBlue"  Grid.Column="0" Grid.Row="2"/>
        <Label Text="bottom center" BackgroundColor="Azure"    Grid.Column="1" Grid.Row="2"/>
        <Label Text="bottom right" BackgroundColor="LigthBlue" Grid.Column="2" Grid.Row="2"/>
    </Grid>
</ContentPage>


in the above we define a grid with 3 rows and 3 columns all of equal weight and this is the result


as we can clearly see the grid fills out all of it's available space and each row and column get's an equal amount of space.

next let's modify our row and column definitions slightly, let's make the top row 3* the middle row 2* and leave the bottom row at just 1* or just *.


<Grid.RowDefinitions>
    <RowDefinition Height="3*"/>
    <RowDefinition Height="2*"/>
    <RowDefinition Height="1*"/>
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>


let's see how this changes our UI


and as expected
  • Top row take ups 3/6 of the space or half
  • Center row takes up 2/6 of the space or or a third of the space
  • Bottom row take up 1/6 of the space or a sixth of the space.
you'll see the same sort of behavior for columns, but let's do something interesting, let's set the bottom row to have a numeric value of 250.


<Grid.RowDefinitions>
    <RowDefinition Height="3*"/>
    <RowDefinition Height="2*"/>
    <RowDefinition Height="250"/>
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

now let's take a look at the result 


as you can see that:
  • Top row takes up 3/5ths of the remaining space
  • Center row takes up 2/5ths of the remaining space
  • Bottom row takes up 200 units of space
Next let's change the first row's width to auto.

<Grid.RowDefinitions>
    <RowDefinition Height="3*"/>
    <RowDefinition Height="2*"/>
    <RowDefinition Height="250"/>
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="auto"/>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>


and the result


we can see that the first column now is just wide enough to fit the longest element namely "button left"

now finally let's drop all of the *'s and replace them with auto's and set the grid's background color to black.

<?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.GridLayoutExample.MainPage">

    <ContentPage.Resources>
        <Style TargetType="Label">
            <Setter Property="HorizontalTextAlignment" Value="Center"/>
            <Setter Property="VerticalTextAlignment" Value="Center" />
        </Style>
    </ContentPage.Resources>

    <Grid BackgroundColor="Black">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="250"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto"/>
            <ColumnDefinition Width="auto"/>
            <ColumnDefinition Width="auto"/>
        </Grid.ColumnDefinitions>

        <Label Text="top left"    BackgroundColor="Yellow"     Grid.Column="0" Grid.Row="0"/>
        <Label Text="top center"  BackgroundColor="Orange"     Grid.Column="1" Grid.Row="0"/>
        <Label Text="top right"   BackgroundColor="Red"        Grid.Column="2" Grid.Row="0"/>

        <Label Text="center left" BackgroundColor="LightGreen" Grid.Column="0" Grid.Row="1"/>
        <Label Text="center center" BackgroundColor="Aqua"     Grid.Column="1" Grid.Row="1"/>
        <Label Text="center right" BackgroundColor="Green"     Grid.Column="2" Grid.Row="1"/>

        <Label Text="bottom left" BackgroundColor="AliceBlue"  Grid.Column="0" Grid.Row="2"/>
        <Label Text="bottom center" BackgroundColor="Azure"    Grid.Column="1" Grid.Row="2"/>
        <Label Text="bottom right" BackgroundColor="LightBlue" Grid.Column="2" Grid.Row="2"/>
    </Grid>
</ContentPage>

now let's take a look at what happens


so we see that our grid fills our entire screen, this however is not the fault of the grid, but the content page, we'll explore this next, but first let's not that the columns and rows without any * heights or width will not fill the area of the grid.

next let's wrap our grid in a stack panel and play with it's horizontal and vertical options

<?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.GridLayoutExample.MainPage">

    <ContentPage.Resources>
        <Style TargetType="Label">
            <Setter Property="HorizontalTextAlignment" Value="Center"/>
            <Setter Property="VerticalTextAlignment" Value="Center" />
        </Style>
    </ContentPage.Resources>

    <StackLayout>
        <Grid BackgroundColor="Black" HorizontalOptions="Center" VerticalOptions="FillAndExpand">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="250"/>
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition Width="auto"/>
            </Grid.ColumnDefinitions>

            <Label Text="top left"    BackgroundColor="Yellow"     Grid.Column="0" Grid.Row="0"/>
            <Label Text="top center"  BackgroundColor="Orange"     Grid.Column="1" Grid.Row="0"/>
            <Label Text="top right"   BackgroundColor="Red"        Grid.Column="2" Grid.Row="0"/>

            <Label Text="center left" BackgroundColor="LightGreen" Grid.Column="0" Grid.Row="1"/>
            <Label Text="center center" BackgroundColor="Aqua"     Grid.Column="1" Grid.Row="1"/>
            <Label Text="center right" BackgroundColor="Green"     Grid.Column="2" Grid.Row="1"/>

            <Label Text="bottom left" BackgroundColor="AliceBlue"  Grid.Column="0" Grid.Row="2"/>
            <Label Text="bottom center" BackgroundColor="Azure"    Grid.Column="1" Grid.Row="2"/>
            <Label Text="bottom right" BackgroundColor="LightBlue" Grid.Column="2" Grid.Row="2"/>
        </Grid>
        <Label BackgroundColor="Purple" Text="Hello world" />
    </StackLayout>
</ContentPage>

now let's see how it renders.

we can observe that the grid layout no longer fills it's space, we used the Horizontal options to center the grid in the vertical StackLayout, and we used the FillAndExpand option to let the Grid take up all of the excess StackLayout real-estate. Finally we gave it a sibling label.

for our final investigation, let's revert back to our first example in which all the rows and columns where relatively layed out to take up an equal amount of space, but this time let's play with column and row span

<?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.GridLayoutExample.MainPage">

    <ContentPage.Resources>
        <Style TargetType="Label">
            <Setter Property="HorizontalTextAlignment" Value="Center"/>
            <Setter Property="VerticalTextAlignment" Value="Center" />
        </Style>
    </ContentPage.Resources>

    <Grid BackgroundColor="Black">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Label Text="top left"    BackgroundColor="Yellow"     Grid.Column="0" Grid.Row="0"/>
        <Label Text="top right"  BackgroundColor="Orange"      Grid.Column="1" Grid.Row="0"
                                                               Grid.ColumnSpan="2"/>

        <Label Text="center left" BackgroundColor="LightGreen" Grid.Column="0" Grid.Row="1"/>
        <Label Text="center" BackgroundColor="Aqua"            Grid.Column="1" Grid.Row="1"
                                                               Grid.RowSpan="2"/>
        <Label Text="center right" BackgroundColor="Green"     Grid.Column="2" Grid.Row="1"/>

        <Label Text="bottom left" BackgroundColor="AliceBlue"  Grid.Column="0" Grid.Row="2"/>
        <Label Text="bottom right" BackgroundColor="LightBlue" Grid.Column="2" Grid.Row="2"/>
    </Grid>
</ContentPage>

let's take a look   


Exactly what we'd expect.

The Grid is the most common layout container for enterprise apps, once you get the hang of it you can quickly generate most form views effectively.