HomeAbout MeEight-Bot

Xamarin.Forms Grid Is Your Best Option

By Michael Stonis
Published in Development
February 25, 2022
2 min read
Xamarin.Forms Grid Is Your Best Option

If you want to build an beautiful Xamarin.Forms app, you are going to need to hack the grid.

In Xamarin.Forms, we have a lot of choices for user interface layouts, but let me simplify it for you: You Pretty much just want to use the Grid. First, throw RelativeLayout and AbsoluteLayout in the trash. RelativeLayout is not super performant. AbsoluteLayout has some special use cases, but, in general, does not scale to all sizes like we need it to. StackLayout is perfect if you have a stack of items to show and you should definitely use it for those situations. FlexLayout is conceptually great and amazingly powerful, but I haven’t had the best luck with the implementation as is. This leaves us with the Grid. Grid is our best all around hitter. If we use it correctly, we can get great performance and we can build extremely complex UIs with relative ease.

Layout Performance

Before I get started, if you haven’t seen this Jason Smith Presentation or read up on Xamarin.Forms performance optimizations, just go do it now. Due to how the layout engine for Xamarin.Forms works, we want to try to make the flattest layout possible and avoid any unnecessary nesting. Nesting becomes a performance problem when our views invalidate their size. It causes them to notify up and down the chain as part of the layout cycle. Michael Ridland has a fantastic article on this topic.

Imagine you wanted to make the following layout. This is fairly complex layout and one that I see a lot of people implement using a series of StackLayouts.

Nested StackLayout Example
Nested StackLayout Example

Consider the following example which is provided via StackLayout. Note how we have three layers of nesting in the outer StackLayout.

<?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="GridHacks.NestedStackLayout">
    <ContentPage.Content>
        <StackLayout>
            <StackLayout Orientation="Horizontal">
                <BoxView Color="Red" HeightRequest="40" HorizontalOptions="EndAndExpand" />
                <BoxView Color="Green" HeightRequest="40" HorizontalOptions="End" />
                <BoxView Color="Blue" HeightRequest="40" HorizontalOptions="End" />
                <StackLayout Orientation="Vertical">
                    <BoxView Color="Red" HeightRequest="40" HorizontalOptions="EndAndExpand" />
                    <BoxView Color="Green" HeightRequest="40" HorizontalOptions="Center" />
                    <BoxView Color="Blue" HeightRequest="40" HorizontalOptions="StartAndExpand" />
                    <StackLayout Orientation="Horizontal">
                        <BoxView Color="Red" HeightRequest="40" VerticalOptions="StartAndExpand" />
                        <BoxView Color="Green" HeightRequest="40" VerticalOptions="Center" />
                        <BoxView Color="Blue" HeightRequest="40" VerticalOptions="End" />
                    </StackLayout>
                </StackLayout>
            </StackLayout>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

An alternative approach would be to use a Grid as shown below. The Grid Control helps us mitigate this issue, as we can put all of our user interface into a single parent and remove all of the excess nesting. Using this technique, the same user interface is generated, but with the Grid, you can see that there is no additional nesting which will go a long way in helping with layout performance. Additionally, you will make to make sure you prefer using the Star and Absolute GridLength units when layout as they will incur the least amount of recalculation.

<?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="GridHacks.NestedStackLayoutGridAlternative">
    <ContentPage.Content>

        <Grid>

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

            <Grid.RowDefinitions>
                <RowDefinition Height="40" />
                <RowDefinition Height="40" />
                <RowDefinition Height="40" />
                <RowDefinition Height="40" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>

            <!-- Row 1 -->
            <BoxView Color="Red" Grid.Row="0" Grid.Column="1" Grid.RowSpan="4" />
            <BoxView Color="Green" Grid.Row="0" Grid.Column="2" Grid.RowSpan="4" />
            <BoxView Color="Blue" Grid.Row="0" Grid.Column="3" Grid.RowSpan="4" />

            <!-- Row 2 -->
            <BoxView Color="Red" Grid.Row="0" Grid.Column="6" />
            <BoxView Color="Green" Grid.Row="1" Grid.Column="5" />
            <BoxView Color="Blue" Grid.Row="2" Grid.Column="4" />

            <!-- Row 3 -->
            <BoxView Color="Red" Grid.Row="3" Grid.Column="4" />
            <BoxView Color="Green" Grid.Row="3" Grid.Column="5" />
            <BoxView Color="Blue" Grid.Row="3" Grid.Column="6" />

        </Grid>

    </ContentPage.Content>
</ContentPage>

Cell Stacking

One of my favorite tricks with the Grid is stacking multiple views into a single cell. I find that a lot of people don’t know that you can do this. The neat part about this is that if you have multiple views in a single grid cell, you can still influence the position of the inner views using the HorizontalOptions and VerticalOptions properties. Using this technique, you can create fairly complex user itnerfaces without any layout nesting. Nice.

Stacked Cell Views
Stacked Cell Views

<?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="GridHacks.StackedGridCell">
    <ContentPage.Content>

        <Grid x:Name="grid"
            BackgroundColor="#616161">

            <Grid.RowDefinitions>
                <RowDefinition Height="4*" />
                <RowDefinition Height="6*" />
            </Grid.RowDefinitions>

            <Image
                Source="https://api.adorable.io/avatars/224/biff@tann.en.png"
                Aspect="AspectFill"
                Grid.Row="0" Grid.Column="0" />

            <Frame
                BackgroundColor="#ffeb3b"
                HasShadow="true"
                CornerRadius="16"
                HorizontalOptions="End" VerticalOptions="Start"
                HeightRequest="16" WidthRequest="16"
                Margin="16"
                Grid.Row="0" Grid.Column="0">

                <Label
                    TextColor="#424242"
                    Text="3"
                    VerticalTextAlignment="Center" HorizontalTextAlignment="Center" />

            </Frame>

            <ContentView
                BackgroundColor="#3f51b5"
                HorizontalOptions="Start" VerticalOptions="End"
                Margin="0,0,16,16" Padding="16">
                <Label Text="Biff Tannen, CEO"
                    FontAttributes="Bold"
                    TextColor="#fafafa" />
            </ContentView>


            <Label
                Text="Other Information"
                FontSize="Large" FontAttributes="Italic"
                HorizontalOptions="Center" VerticalTextAlignment="Center"
                Grid.Column="0" Grid.Row="1" />

        </Grid>
    </ContentPage.Content>
</ContentPage>

Controlling Z-Index

It is worth noting that in Xamarin.Forms, there is no real way to control the Z-Index of controls in a parent. This will be Solved in MAUI, but until we get there we only have a few options. The primary way to control Z-Index is by ordering the way that children are added to a Grid. The later that items are added to a grid, the higher up on the display they will be. So, if you want to set something as an underlay/background, add those controls first. Alternatively, in code we can call the Grid’s RaiseChild and LowerChild methods to raise a child to the top or lower it to the bottom.

Wrap-up

Hopefully this gives you some ideas of what you can do with the Grid and why you should consider using it over any of the available layouts.

Original Header Photo by Ben Neale on Unsplash


Tags

xamarin.formstechnology
Previous Article
Xamarin.Forms Renderer Property
© 2022, All Rights Reserved.

Blog

Social Media