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.
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.
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"?><ContentPagexmlns="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"?><ContentPagexmlns="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>
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.
<?xml version="1.0" encoding="UTF-8"?><ContentPagexmlns="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><ImageSource="https://api.adorable.io/avatars/224/biff@tann.en.png"Aspect="AspectFill"Grid.Row="0" Grid.Column="0" /><FrameBackgroundColor="#ffeb3b"HasShadow="true"CornerRadius="16"HorizontalOptions="End" VerticalOptions="Start"HeightRequest="16" WidthRequest="16"Margin="16"Grid.Row="0" Grid.Column="0"><LabelTextColor="#424242"Text="3"VerticalTextAlignment="Center" HorizontalTextAlignment="Center" /></Frame><ContentViewBackgroundColor="#3f51b5"HorizontalOptions="Start" VerticalOptions="End"Margin="0,0,16,16" Padding="16"><Label Text="Biff Tannen, CEO"FontAttributes="Bold"TextColor="#fafafa" /></ContentView><LabelText="Other Information"FontSize="Large" FontAttributes="Italic"HorizontalOptions="Center" VerticalTextAlignment="Center"Grid.Column="0" Grid.Row="1" /></Grid></ContentPage.Content></ContentPage>
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.
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