Codementor Events

Prettier lists in Xamarin Forms

Published Jan 04, 2018Last updated Jul 03, 2018

Achieving better looks with Custom Renderers.


Xamarin Forms is great. It provides us all of the essential UI elements that a simple app can have. But in most of the cases, we do want to customise our UI to suit our branding, or just simply make it prettier. We can achieve that by creating custom renderers for every platform (we’re going to focus on iOS and Android only).

So let’s say we want to extend the looks of the ListView to show something like this:

As we can see, we have two labels with different colors and a view on the left that represents some form of indication.

So, first of all, we need to create our ViewCell class in the PCL project. Let’s name it ColorStripeCell. Inside we’re going to define 3 variables that’s going to hold our data for the Name, Description and Stripe Color. All of them will be strings. We’ll also define BindingProperty variables for each of those 3. At the end our class would look like this:

public class ColorStripeCell : ViewCell
{
     public static readonly BindableProperty NameProperty =
     	BindableProperty.Create("Name", typeof(string), typeof(ColorStripeCell), "");
 
     public string Name
     {
     	get
     	{
        	return (string)GetValue(NameProperty);
        }
        set
        {
        	SetValue(NameProperty, value);
        }
     }
 
     public static readonly BindableProperty DescriptionProperty =
     	BindableProperty.Create("Description", typeof(string), typeof(ColorStripeCell), "");
 
     public string Description
     {
         get
         {
             return (string)GetValue(DescriptionProperty);
         }
         set
         {
             SetValue(DescriptionProperty, value);
         }
     }
 
     public static readonly BindableProperty StripeColorProperty =
     	BindableProperty.Create("StripeColor", typeof(string), typeof(ColorStripeCell), "");
 
     public string StripeColor
     {
         get
         {
             return (string)GetValue(StripeColorProperty);
         }
         set
         {
             SetValue(StripeColorProperty, value);
         }
     }
 
     public ColorStripeCell()
     {
 
     }
 
     public ColorStripeCell(string name, string description, string stripeColor)
     {
         Name = name;
         Description = description;
         StripeColor = stripeColor;
     }
}

This is the class that we’re going to populate our TableView with. So let’s do that!

var Section = new TableSection();
Section.Add(new ColorStripeCell("Region of Halton", "Truck 16-48", "#e74c3c"));
ourTableView.Root.Add(Section);

We’re populating our TableView with some data using our ColorStripeCell class. But in order to actually show it we need to create the custom renderers for both platforms. Now comes the platform-specific part!


iOS

Time to build the custom renderer for iOS! Let’s create a new folder inside our iOS project and call it Renderers. Inside that folder we’ll create our custom renderer, which is a C# class.

As you can see, you can have as many custom renderers as you want. Let’s name ours ColorStripeCellRenderer. This class must extend the ViewCellRenderer class. That class provides us with the GetCell method in which we develop our table cell. So let’s override it! We can see that GetCell gives us 3 arguments: Cell item, UITableViewCell reusableCell and UITableView tv. We’re going to use the first one Cell item to cast it to our cell that we created before in the PCL project:

var x = (ColorStripeCell)item;

This variable x now holds the data for each cell that we provide (Name, Description and Stripe Color). Before we continue, we need to make another class in our iOS project that’s going to take care of the cell itself. Let’s create another folder and call it Cells. Inside we’ll create our class and name it NativeiOSColorStripeCell that’s going to extend UITableViewCell. In this class, we will draw our cell. So let’s create two UILabel instances and one UIView for our color stripe. We’ll define them in the constructor of our class and then add them to our ContentView. So, your constructor should look like this:

public NativeiOSColorStripeCell(NSString cellId) : base(UITableViewCellStyle.Default, cellId)
{
      SelectionStyle = UITableViewCellSelectionStyle.Gray;
      BackgroundColor = UIColor.Clear;
 
      ContentView.BackgroundColor = UIColor.Clear;
 
      stripeView = new UIView();
 
      nameLabel = new UILabel
      {
          TextColor = UIColor.White,
          MinimumFontSize = 24,
          BackgroundColor = UIColor.Clear
      };
 
      descriptionLabel = new UILabel
      {
          TextColor = "#7291A5".ToUIColor(),
          MinimumFontSize = 17,
          BackgroundColor = UIColor.Clear
      };
 
      ContentView.Add(stripeView);
      ContentView.Add(nameLabel);
      ContentView.Add(descriptionLabel);
}

Make sure to declare your UI variables outside the constructor, because we’ll be using them in two more methods. First one is our method for updating the text and color of our cell:

public void UpdateCell(string caption, string subtitle, UIColor color)
{
      nameLabel.Text = caption;
      descriptionLabel.Text = subtitle;
      stripeView.BackgroundColor = color;
}

We use this method in our Custom Renderer class to get the data for our cell and apply it. Next, we do the actual drawing with the next method:

public override void LayoutSubviews()
{
    base.LayoutSubviews();
 
    stripeView.Frame = new CGRect(10, 10, 2, ContentView.Bounds.Height - 20);
    nameLabel.Frame = new CGRect(18, 13, ContentView.Bounds.Width - 12, 25);
    descriptionLabel.Frame = new CGRect(18, 40, ContentView.Bounds.Width - 12, 20);
}

LayoutSubviews gets called automatically before rendering. As you can see we define the frames of our elements in this method. So, our iOS cell has 3 methods:

  1. Constructor — Initializes the UI elements and adds them to ContentView.
  2. UpdateCell — Sets the data to our UI elements, like text, color etc…
  3. LayoutSubviews  — Defines the frames(positions) of our UI elements.

Since our cell is completed, let’s go back to our Custom Renderer and cast the reusableCell argument to it right below the initialization of x:

NativeiOSColorStripeCell c = reusableCell as NativeiOSColorStripeCell;

We need to make sure it’s not null, otherwise create a new instance of our cell and pass the reusable identifier as an argument:

if (c == null)
{
    c = new NativeiOSColorStripeCell(new NSString("ColorStripeCell"));
}

Next, let’s create our UIColor from the hex that we got:

UIColor color = null;
if (!String.IsNullOrWhiteSpace(x.StripeColor))
{
     color = color.FromHexString(x.StripeColor);
}

The method FromHexString is a custom method that gets the color hex as string and returns a UIColor. For the sake of simplicity, you can use the constructor of UIColor(nfloat red, nfloat green, nfloat blue, nfloat alpha).

Now, since we have our color built, let’s call the UpdateCell method on our cell and pass our data as arguments:

c.UpdateCell(x.Name, x.Description, color);

Now we can alter the properties of the UITableView that’s provided in the arguments.

tv.RowHeight = 75;
tv.SeparatorColor = "#0B495F".ToUIColor();
 
tv.SectionIndexBackgroundColor = "#0B495F".ToUIColor();
tv.SectionIndexColor = "#7291A5".ToUIColor();

ToUIColor is also a custom method that gets the hex string and turns it into a UIColor.

Finally! Our cell is ready and we can return it!

return c;

Your custom renderer is done, and it looks like this:

public class ColorStripeCellRenderer : ViewCellRenderer
{
     static NSString rid = new NSString("ColorStripeCell");
 
     public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
     {
         var x = (ColorStripeCell)item;
 
         NativeiOSColorStripeCell c = reusableCell as NativeiOSColorStripeCell;
 
         if (c == null)
         {
             c = new NativeiOSColorStripeCell(rid);
         }
 
         UIColor color = null;
         if (!String.IsNullOrWhiteSpace(x.StripeColor))
         {
             color = color.FromHexString(x.StripeColor);
         }
         c.UpdateCell(x.Name, x.Description, color);
 
         tv.RowHeight = 75;
         tv.SeparatorColor = "#0B495F".ToUIColor();
 
         tv.SectionIndexBackgroundColor = "#0B495F".ToUIColor();
         tv.SectionIndexColor = "#7291A5".ToUIColor();
 
         return c;
     }
}

But, how will Xamarin know that this is our custom renderer? Well, we’ll tell it by adding this line between the namespace declaration of our custom renderer and the using statements:

[assembly: ExportRenderer(typeof(ColorStripeCell), typeof(ColorStripeCellRenderer))]
namespace OurApp.iOS
{
    public class ColorStripeCellRenderer : ViewCellRenderer
    {
        ...

Basically it’s a dependency injection. We’re telling Xamarin Forms to use this class to render our cell ColorStripeCell.

And that’s it for iOS! Make a run and check it out!


Android

Now you get the point of the custom renderer for iOS, what it does and how to build it. Well, custom renderers for Android work the same way!

Let’s open our Droid project and create a new folder called Renderers. Inside we’ll create our renderer class called ColorStripeCellRenderer and extend the ViewCellRenderer. Unlike iOS, we need to override the GetCellCore method. This is the Android equivalent of iOS’s GetCell.

protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, Android.Views.ViewGroup parent, Android.Content.Context context)

We’ll use the first argument Cell item to cast it to our ColorStripeCell class:

var x = (ColorStripeCell)item;

Now, instead of creating a C# class for our cell, we’ll create a .axml file where we define the layout of our cell (because it’s Android!). Get into Resources > layout and create it (ColorStripeCell.axml). I’m just going to paste the layout code:

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:padding="15dp">
     <View
         android:id="@+id/llColorStripe"
         android:layout_width="2dp"
         android:layout_height="match_parent"
         android:background="@color/abc_search_url_text_normal" />
     <LinearLayout
         android:orientation="vertical"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_marginLeft="10dp">
         <TextView
             android:id="@+id/Name"
             android:textSize="22sp"
             android:textColor="#FFF"
             android:background="@android:color/transparent"
             android:text="Region of Halton"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
         <TextView
             android:id="@+id/Description"
             android:textSize="17sp"
             android:textColor="#7291A5"
             android:background="@android:color/transparent"
             android:text="Truck 16-48"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
     </LinearLayout>
 </LinearLayout>

Now since we have the layout, let’s use LayoutInflater to initialize our cell:

Android.Views.View v =
    LayoutInflater.FromContext(context)
    		  .Inflate(Resource.Layout.ColorStripeCell, parent, false);

We can now use “v” to get our subviews and setup the text and color and return our cell:

Android.Views.View colorStripe = v.FindViewById<Android.Views.View>(Resource.Id.llColorStripe);

TextView Name = v.FindViewById<TextView>(Resource.Id.Name);
TextView Description = v.FindViewById<TextView>(Resource.Id.Description);

Name.Text = x.Name;
Description.Text = x.Description;
colorStripe.SetBackgroundColor (Android.Graphics.Color.ParseColor (x.StripeColor));

return v;

Now what we need to do is tell Xamarin Forms to use our new renderer for ColorStripeCell:

[assembly: ExportRenderer(typeof(ColorStripeCell), typeof(ColorStripeCellRenderer))]
namespace OurApp.Droid
{
    public class ColorStripeCellRenderer : ViewCellRenderer
    {
        ...

And that’s it! You’re done! Make a run and check it out.


Recap

Basically what we did is we created a ColorStripeCell class in our PCL class and we used it to populate our TableView. After that we created our custom renderers and told Xamarin Forms to use them to render ColorStripeCell. The key methods in our custom renderers for Android and iOS were GetCellCore and GetCell. We defined how our cell is going to look, applied the data to it and returned it.

There you go! Now you have a Xamarin Forms app with a fancy looking list!

Discover and read more posts from Lazar Nikolov
get started