
May 23, 2022
Dynamic XAML in Xamarin.Forms Applications
Most of the time, we software developers focus on optimizing our code. We want it to be fast, easy to understand, and easy to maintain. Many of those codes are related to data handling, API queries, record updates, etc. But how many times do we worry about optimizing the user interface?
When we navigate to a screen in any application, we usually load a certain amount of information. If the load is slow, the first culprit is the process that retrieves the information that should be displayed on that page, but this is not always the case. Sometimes the slowness is due to the view not being programmed properly and doing something called “overdraw”.
“Overdrawing” occurs when your app draws the same pixel more than once within the same frame. Your app might be doing more rendering work than necessary, which can be a performance problem due to extra GPU effort to render pixels that won’t be visible to the user.
Fortunately, Android has some tools to identify and correct those scenarios.
With this, you can recognize where overdrawing is occurring in your application.
This application shows a list of some employees here at Trailhead. As you can see, it shows their profile picture, name, position, and a brief summary of their expertise.
Despite being a simple application, the Overdrawing tool is showing almost everything as red. This is because we used a non-optimized layout to draw the view.
Let’s take a look at the Rendering Speed.
As we can see, it’s quite high. A bit over half of the available graphic processing power just to load and update this screen.
Now, let’s optimize the code from this:
<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:local="clr-namespace:Demo.ViewModels" xmlns:model="clr-namespace:Demo.Models" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Demo.Views.ItemsPage" Title="{Binding Title}" x:Name="BrowseItemsPage"> <ContentPage.ToolbarItems> <ToolbarItem Text="Add" Command="{Binding AddItemCommand}" /> </ContentPage.ToolbarItems> <ContentPage.Content> <ListView ItemsSource="{Binding Items}" SelectionMode="None" HasUnevenRows="True"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Frame Padding="10" BackgroundColor="WhiteSmoke"> <StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand" BackgroundColor="WhiteSmoke"> <StackLayout Orientation="Horizontal"> <Frame CornerRadius="100" Padding="0" IsClippedToBounds="True" HorizontalOptions="Center"> <Image Source="{Binding AvatarUrl}" HeightRequest="100" /> </Frame> <StackLayout Padding="10"> <StackLayout Orientation="Horizontal"> <Label Text="{Binding Name}" BackgroundColor="WhiteSmoke" FontSize="21" /> <Label Text="{Binding LastName}" BackgroundColor="WhiteSmoke" FontSize="21" /> </StackLayout> <Label Text="{Binding Position}" BackgroundColor="WhiteSmoke" LineBreakMode="NoWrap" FontSize="21" Padding="5" /> </StackLayout> </StackLayout> <Label Text="{Binding Description}" BackgroundColor="WhiteSmoke" FontSize="18" Padding="5" /> </StackLayout> </Frame> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage.Content> </ContentPage>
To this:
<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:local="clr-namespace:Demo.ViewModels" xmlns:model="clr-namespace:Demo.Models" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Demo.Views.ItemsPage" Title="{Binding Title}" x:Name="BrowseItemsPage"> <ContentPage.ToolbarItems> <ToolbarItem Text="Add" Command="{Binding AddItemCommand}" /> </ContentPage.ToolbarItems> <RefreshView x:DataType="local:ItemsViewModel" Command="{Binding LoadItemsCommand}" IsRefreshing="{Binding IsBusy, Mode=TwoWay}"> <CollectionView x:Name="ItemsListView" ItemsSource="{Binding Items}" SelectionMode="None"> <CollectionView.ItemTemplate> <DataTemplate> <Grid x:DataType="model:Item" Padding="10"> <Grid.RowDefinitions> <RowDefinition Height="25" /> <RowDefinition Height="75" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="120" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Image Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" HorizontalOptions="Center" Source="{Binding AvatarUrl}"> <Image.Clip> <EllipseGeometry Center="50,50" RadiusX="50" RadiusY="50" /> </Image.Clip> </Image> <Label Grid.Row="0" Grid.Column="1" Text="{Binding FullName}" FontSize="21" /> <Label Grid.Row="1" Grid.Column="1" Text="{Binding Position}" FontSize="21" /> <Label Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Description}" FontSize="18" /> </Grid> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </RefreshView> </ContentPage>
In this simple example, we’ve changed only the view. Now let’s take a look at the results.
As you can see, we don’t have any red overlays now. It means we’re using the right amount of code needed to draw this page. How about the rendering speed?
We’ve cut in half the amount of required GPU time needed for our app. Even if you have high-end devices, this means our screen will load twice as fast compared to our previous version.
Thanks for reading!
Leave a comment