Tuesday, August 25, 2015

Using iOS standard icons in Xamarin Forms

Have you ever wished for using the standard iOS icons in the toolbar for Xamarin Forms applications? Then you are reading the correct blog post. If not, then you are in the wrong place.

The problem

We want to utilize the built in icons for iOS in our Xamarin Forms application to create something like the image below.



The solution

The good news is that is isn't really that complicated. Simply create a custom renderer and add some behavior to the NavigationRenderer.

First, the Xaml

The definition of our view looks like this.

xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    Title = "Welcome"
    x:Class="Test.MyPage">

    <ContentPage.ToolbarItems>
        <ToolbarItem Name="Add" />
        <ToolbarItem Name="Camera" />
    </ContentPage.ToolbarItems>

    <ContentPage.Content>
        <Label Text="Wow, that's cool!" HorizontalOptions="Center" VerticalOptions="Center" />
    </ContentPage.Content>

</ContentPage>


The key part here is to name your ToolbarItems to something useful and something that we can reference in the custom renderer. You also might want to make sure that the name works on Android and Windows Phone since those platforms won't be affected by this change.

Then the renderer

Being a swede, I have trouble saying the word Renderer... Rendererrerr... Anyhow, this is what it looks like in code. The key is to look at the title for each UIBarButtonItem and replace the entire button with a new one. So we first define a new list to hold our new buttons and then recreate them, one by one to finally assign the new list to the NavigationItem.

The renderer goes in the iOS project since it's iOS specific.

[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationRenderer))]

namespace ToolbarApp.iOS.Renderers
{
    public class CustomNavigationRenderer : NavigationRenderer
    {

        public override void PushViewController(UIKit.UIViewController viewController, bool animated)
        {
            base.PushViewController(viewController, animated);

            var list = new List<UIBarButtonItem>();

            foreach (var item in TopViewController.NavigationItem.RightBarButtonItems)
            {
                if(string.IsNullOrEmpty(item.Title))
                {
                    continue;
                }

                if (item.Title.ToLower() == "add")
                {
                    var newItem = new UIBarButtonItem(UIBarButtonSystemItem.Add)
                    {
                        Action = item.Action,
                        Target = item.Target
                    };
                    
                    list.Add(newItem);
                }

                if (item.Title.ToLower() == "camera")
                {
                    var newItem = new UIBarButtonItem(UIBarButtonSystemItem.Camera)
                        {
                            Action = item.Action,
                            Target = item.Target
                        };

                    list.Add(newItem);
                }

                TopViewController.NavigationItem.RightBarButtonItems = list.ToArray();
            }
        }
    }
}


Summary

It's pretty simple to utilize platform specific stuff in Forms and you should do that in order keep that native feeling. The key to success is Custom Renderers. Learn to use them and you'll excel in all parts of your life!

Resources

The original post from the Xamarin Forum. Thanks goes to Torben Kruse for initially answering this question.

A sample project for trying it out without coding a line.

6 comments:

  1. Can you post a sample project for us newbs? :) Gettign an unresolved ref on this line:

    public override void PushViewController(UIKit.UIViewController viewController, bool animated)

    It cant resolve UIKit.UIViewController

    Thank you.

    When I resolve it to UIKit.UIViewController

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Here's the project.
      https://dl.dropboxusercontent.com/u/48287660/blogexamples/StandardIcons.zip

      Delete
  2. It works wonderful! I'm wondering if you have the render for Android as well to use their system icons.

    Please

    Thanks in advance

    ReplyDelete
    Replies
    1. Sorry for a late reply. I don't have one set up at the moment but I guess it would be just about the same thing?

      Delete
  3. This comment has been removed by the author.

    ReplyDelete