Replicating Habit Tracker UI with ProgressRing in Uno Platform

This article will review the essential steps of replicating a user interface using Uno Platform XAML elements. We’ve also incorporated some refinements to the original design, emphasizing the functionalities of essential elements like ProgressRing, Borders, TextBlock, and more.

This article will cover

  • 1. Breaking down the UI into blocks will help you work more methodically and give you insight into which elements to incorporate.
  • 2. Coding each block step by step: After identifying the visual blocks to develop, we will build our UI.
  • 3. Implementing ProgressRing control available in Uno Platform.

TLDR: Build a mobile user interface using Uno Platform, covering both the analysis of the UI and the step-by-step coding process for different UI elements, including implementing a ProgressRing control.

Breaking Down the Visual Structure of the UI

First, let’s take a look at the Habit Tracker UI we will replicate based on a home screen idea design by Alexandre Naud

Habit Tracker UI Home screen
Habit Tracker UI Design by Alexandre Naud

To gain a better understanding of how to translate each UI block into functional code, we will divide the UI structure into the following two blocks:

header design and list design
Breaking down our UI

Step 1 - Main Layout Structure

To start, we’ll create the main layout structure using a Grid to house all the code blocks described in this article. 

				
					<!--Main layout structure -- >

<Grid Padding="10,20,10,0" ColumnSpacing="20" RowDefinitions="Auto,*" ColumnDefinitions="Auto,*,Auto" Background="Black">

          <!-- Add the Header code block-- > 
          <!-- Add the Home ideas list code block -- >  

</Grid>

				
			

✍️ The Grid consists of two rows: the first row contains the Header block, while the second row houses the List block. Additionally, we have three columns primarily to organize the elements of the header block, while for the list block, we will cover the three columns.

Follow Along with our Code Samples
Did you know you can access the code sample for this tutorial in our Uno.Samples repo? It's an excellent resource for hands-on experience with the concepts we're discussing.

Try it and see how to apply what you've learned so far!

Code Explanation

Step 2 - Building our Header

📋 Make sure to follow the step-by-step instructions carefully to ensure that your code looks perfect!

Let’s begin now that we have the main layout structure ready! This section will focus on building the necessary elements for the header block. It is made up of three different components:

  1. Order Button
  2. Title
  3. Add Button

Let’s pinpoint exactly where these elements are located.

breaking down header

Translating our Header into Code

				
					<!--1. Header -->
  	 
<!-- Order Button -->

<Button Grid.Column="0" Grid.Row="0" Background="#282929" Height="40" Width="40" CornerRadius="5" Margin="10,0,0,0">
         	<Image Source="Assets/add"/>
</Button>
       	 
<!--Title-->

<TextBlock Text="Combiien" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" Foreground="White" VerticalAlignment="Center"/>
       	 
<!-- Add Button-->

<Button Grid.Column="2" Grid.Row="0" Background="#282929" Height="40" Width="40" CornerRadius="5" Margin="0,0,10,0">
        	<Image Source="Assets/order"/>
</Button>

<!-- Add here the following block of code -- >

				
			

By implementing the above code, you should have a result like the screen shown below:

Step 3 - Habit List

Our second block contains different types of visual elements, which are the following:

  • List of habits: This will contain all the elements of the block
  • Habit detail card contains the following elements:
    • Progress information: Show the percentage in text, and we will be exploring the ProgressRing to indicate that the process is still ongoing.
    • Card’s Title and Description
    • Card’s Amount and type
    • Card’s actions
breakdown of task blocks

Building our List

Our first step for this block is creating the primary list encompassing all Home Ideas cards. To fill this list, we must first define the model we will use. In this case, it is called Ideas.cs, and it contains the following attributes:

				
					public class Ideas
	{
    	public string Percentage { get; set; }
    	public string PercentageColor { get; set; }
    	public string Title { get; set; }
    	public string Description { get; set; }
    	public string Amount { get; set; }
    	public string AmountType { get; set; }
	}

				
			

Moving on, we’ll populate this model with mock data. We’ll use a simple example to display the list by filling it directly in the Mainpage.xaml.cs file. However, you can choose the method that works best for you. 

Once we’re in the MainPage.xaml.cs file, we’ll create a new method called GenerateInfo, which will look like this:

				
					public readonly ObservableCollection<Ideas> ideas;

 public void GenerateInfo()
    	{
        	// Home ideas list
        	ideas.Add(new Ideas() { Percentage = "50%", PercentageColor = "#ffa500", Title = "Walking", Description = "How Many in May?", Amount = "24.08", AmountType = "km" });
        	ideas.Add(new Ideas() { Percentage = "50%", PercentageColor = "#164734", Title = "Vacations in France", Description = "Budget with Emma", Amount = "72.000", AmountType = "USD" });
        	ideas.Add(new Ideas() { Percentage = "50%", PercentageColor = "#01abf3", Title = "Reading", Description = "Goal: Read 16 books a year", Amount = "12", AmountType = "/16" });
        	ideas.Add(new Ideas() { Percentage = "50%", PercentageColor = "#ff4582", Title = "Quit Smoking", Description = "Last cigare on 0420", Amount = "24.08", AmountType = "km" });
        	ideas.Add(new Ideas() { Percentage = "50%", PercentageColor = "#ffa500", Title = "Walking", Description = "How Many in May?", Amount = "24.08", AmountType = "km" });
        	ideas.Add(new Ideas() { Percentage = "50%", PercentageColor = "#164734", Title = "Vacations in France", Description = "Budget with Emma", Amount = "72.000", AmountType = "USD" });
}
				
			

Then you just have to call the list in your MainPage.xaml:

				
					public MainPage()
    	{
        	this.InitializeComponent();
        	ideas = new ObservableCollection<Ideas>();
        	GenerateInfo();
    	}
				
			

Now that we have our mock data, we need to know how to display it on the screen. To achieve this, we will implement a ListView and include a StackPanel to organize the remaining elements.

				
					<!--2. Home list ideas -->
<ListView Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{x:Bind ideas}" SelectionMode="None" Padding="0,20,0,0">
     <ListView.ItemTemplate>
            	<DataTemplate x:DataType="local:Ideas">
                	<StackPanel Margin="0,5">

                    	   <!-- Add the Ideas details card --> 	
 
                    </StackPanel>
            	</DataTemplate>
        </ListView.ItemTemplate>
</ListView>

				
			

Ideas Detail Card

This information will be divided into two Borders elements, so add the following code right in the part of the previous block that says “<!– Add the Ideas details card — >”

As you can see, I have left comments within each block to guide you in locating the remaining elements needed to build.

				
					<!-- Main Information -->
<Border Background="#282929" BorderThickness="0.8" Height="65" CornerRadius="8,8,0,0" HorizontalAlignment="Stretch" Margin="0,5,0,0">
           <Grid RowDefinitions="Auto,Auto" ColumnDefinitions="Auto,*,Auto" Padding="20,10"          
                     RowSpacing="5" VerticalAlignment="Center">

                       <!-- Add the Progress Information -- > 
                       <!-- Add the Card’s title and description -- > 
                       <!-- Add the Card’s amount and type -- > 

          </Grid>                             
</Border>

<!--Actions Information-->
<Border Background="#141414" BorderThickness="0.8" Height="30" CornerRadius="0,0,8,8" HorizontalAlignment="Stretch">
         <Grid RowDefinitions="Auto" ColumnDefinitions="*,*,*" Padding="20,0" RowSpacing="5" VerticalAlignment="Center">

                        <!-- Add the Card’s actions-- > 	
	 
         </Grid>
</Border>

				
			
Did you know?
There are two implementations of the ProgressRing control available in Uno Platform:

Windows.UI.Xaml.Controls.ProgressRing - "WUX ProgressRing" - implementation based on the built-in control in Universal Windows Platform, with support for both native & UWP styling.

Microsoft.UI.Xaml.Controls.ProgressRing - "MUX ProgressRing", implementation based on WinUI 2.x and WinUI 3.

Progress Information

To display progress in text, I have used a TextBlock. To indicate that a process is in progress, I have used a Progress Ring control. This control keeps spinning like an animation. With Uno Platform, you can use the ProgressRing control, which is shaped like a ring and fills progressively to indicate the progress of a preset action.

You can learn more about by accessing the ProgressRing documentation from Uno Platform.

Card Title and Description

				
					<!-- Graphic information -->
<ProgressRing Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" VerticalAlignment="Center" Foreground="{x:Bind PercentageColor}" Height="50" Width="50" Margin="0,0,15,0" />

<!-- Text information -->
<TextBlock Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" VerticalAlignment="Center" Text="{x:Bind Percentage}" FontWeight="Bold" FontSize="12" Foreground="{x:Bind PercentageColor}" Padding="15,0,10,0"/>
                           	
<!-- Add here the following block of code -- >

				
			
				
					 <TextBlock Grid.Row="0" Grid.Column="1" Text="{x:Bind Title}" VerticalAlignment="Bottom" Foreground="White" FontSize="12"/>

<TextBlock Grid.Row="1" Grid.Column="1" Text="{x:Bind Description}" VerticalAlignment="Top" Foreground="#8d8e8f" FontSize="12"/>
                          	
<!-- Add here the following block of code -- >

				
			

Card Amount and Type

Optimizing elements: You have two options when faced with two text pieces of information on the same line but with different styles. You can create two TextBlocks or use a single TextBlock with different visual characteristics added to the text using Run. The latter is very optimal, so let’s see how to do it:

				
					<TextBlock Grid.Row="0" Grid.Column="2" Grid.RowSpan="2"  VerticalAlignment="Center">
          <Run Text="{x:Bind Amount}" Foreground="White" FontSize="18"/>
          <Run Text="{x:Bind AmountType}" Foreground="#abadae" FontSize="11"/>
</TextBlock>

				
			

Card Actions

We have reached the final step. Now, go to the other Border Control section labeled as “ <! — Add the Card’s actions — >“, and include the following three TextBlocks:

				
					<TextBlock Grid.Row="1" Grid.Column="0" Text="Less" Foreground="#8d8e8f" FontSize="12" HorizontalAlignment="Left"/>

<TextBlock Grid.Row="1" Grid.Column="1" Text="Options" Foreground="#8d8e8f" FontSize="12" HorizontalAlignment="Center"/>

<TextBlock Grid.Row="1" Grid.Column="2" Text="More" Foreground="#8d8e8f" FontSize="12" HorizontalAlignment="Right"/> 

				
			

Final Result

Next Steps

Just a quick reminder that this development is designed to work seamlessly on both Android and iOS platforms, giving you the same app experience on both. You can access the complete project from the GitHub Sample repository.

To upgrade to the latest release of Uno Platform, please update your packages to 4.10 via your Visual Studio NuGet package manager! If you are new to Uno Platform, following our official getting started, guide is the best way to get started. (5 min to complete)

Leomaris Reyes

Leomaris Reyes

Follow Leomaris on Twitter

Tags:

Uno Platform 5.2 – True Single Project, enhanced Skia renderers, Multi Window and .NET 9 support , and more! See what’s new