Building a Dynamic Navigation Bar for iOS Apps Using Xamarin

Introduction

When developing applications, we come across requirements, such as displaying the count of new notifications, or the number of items in the cart on the toolbar. In this article, we will solve this problem in Xamarin forms with some elements at the platform level. This article is focused on iOS implementation.

Description

To begin with, let’s start with creating a “Multiplatform” Xamarin forms application named “CustomNotificationIndicator.” It creates two projects, as shown in Figure 1:

Creating a "Multiplatform" Xamarin forms application
Figure 1: Creating a “Multiplatform” Xamarin forms application

Xamarin Form Level Changes

In the “CustomNotificationIndicator” project, add a ‘Forms Content Page Xaml’ file with code behind named ‘CustomNotificationIndicatorPage.xaml,’ as shown in Figure 2:

Adding a 'Forms Content Page Xaml' file
Figure 2: Adding a ‘Forms Content Page Xaml’ file

In the CustomNotificationIndicatorPage.Xaml file, add a button to increase the count of the number of notifications displayed on the toolbar.

<Button Command="{Binding AddNotificationCommand}" Text="Click Me" />

In the code behind file, declare an event that will be defined in the page renderer at the platform level.

1. public event EventHandler<string> ToolbarNotificationChangedEvent;

In the App.Xaml.cs resolve the page model, as demonstrated below:

2. var landingPage = new FreshNavigationContainer(
   FreshPageModelResolver.ResolvePageModel
      <CustomNotificationIndicatorPageModel>());

There are few more changes required in the code behind; however, let’s first look at the page model implementation. For this example, we are using FreshMVVM. Now, add a new class file named “CustomNotificationIndicatorPageModel.cs;” this will be view model file for the Xaml file created above. In the page model, we define a Command to handle the click event.

3. public ICommand AddNotificationCommand {get; set;}

In the constructor, we define the Command implementation, as follows:

4. public CustomNotificationIndicatorPageModel()
   {
      AddNotificationCommand = new Command(async () =>
         await AddNotificationValue());
   }

Define a static variable for type int that stores the count of the number of times the button was tapped. Also, declare an event object that is triggered whenever the count is changed.

5. static int NotifyCount;
6. public event EventHandler<string>
      NotificationValueChangedEvent;

The definition of “AddNotificationValue” is as below:

7. private async Task AddNotificationValue()
   {
      NotifyCount++;

      if (NotificationValueChangedEvent != null)
         NotificationValueChangedEvent.Invoke(this,
            NotifyCount.ToString());
   }

In this method, the static variable defined in Step 5 is incremented by 1 every time user taps the button. In addition, it also invokes the ‘NotificationValueChangedEvent’ defined in the Xaml code behind. The code in the CustomNotificationIndicatorPage.xaml.cs is as follows:

8. protected override async void OnBindingContextChanged()
   {
      base.OnBindingContextChanged();

      var pm = (CustomNotificationIndicatorPageModel)
         this.BindingContext;

      if (pm != null)
      {
         pm.NotificationValueChangedEvent +=
            Pm_NotificationValueChangedEvent;

      if (this.ToolbarItems.Count == 0)
      {
         this.ToolbarItems.Clear();

         this.ToolbarItems.Add(new ToolbarItem()
         {
            Order = ToolbarItemOrder.Default,
            Command = pm.NotificationClickCommand
         });

      }
   }

}

In this method, we first retrieve the binding context—the page model. Define an implementation for the “NotificationValueChangedEvent” and add a toolbaritem with a command associated with it. The implementation method for the NotificationValueChangedEvent is:

9. void Pm_NotificationValueChangedEvent(object sender, string e)
   {
      if (ToolbarNotificationChangedEvent != null)
         ToolbarNotificationChangedEvent.Invoke(this, e);
   }

This method, in turn, invokes the ToolbarNotificationChangedEvent event defined in the platform-specific page renderer.

Let’s summarize all the actions done so far. We have a page model named ‘CustomNotificationIndicatorPageModel.cs‘ that has an event named ‘NotificationValueChangedEvent,’ which is implemented in code behind file ‘CustomNotificationIndicatorPage.xaml.cs.’ The “AddNotificationValue” method is defined in the view model; this method increments the count and notifies the code behind page about the change. The changed value is passed as an event argument. The code behind page declares an event named ‘ToolbarNotificationChangedEvent;’ the implementation for this event resides in the PageRenderer—at the platform specific level.

Platform Level Changes

In the CustomNotificationIndicator.iOS project, add a class file named ‘NotificationPageRenderer.’ The code is as below:

 1. [assembly: ExportRenderer(typeof(CustomNotificationIndicatorPage),
       typeof(NavPageNavigator))
 2. namespace CustomNotificationIndicator.iOS
 3. {
 4.    public class NavPageNavigator : PageRenderer
 5.    {
 6.       protected override void OnElementChanged
             (VisualElementChangedEventArgs e)
          {
 7.          base.OnElementChanged(e);
 8.          var customPage =
                (CustomNotificationIndicatorPage)Element;
 9.          customPage.ToolbarNotificationChangedEvent +=
             customPage_ToolbarNotificationChangedEvent;
          }

10.       void customPage_ToolbarNotificationChangedEvent
             (object sender, string e)
         {
            var uiBarBtn =
               NavigationController.TopViewController.
               NavigationItem.RightBarButtonItem;
            var uiButton = (UIButton) uiBarBtn.CustomView;
            if (uiButton != null)
            {
               uiButton.SetTitle(e, UIControlState.Normal);
               uiButton.SetTitleColor(UIColor.Black,
                  UIControlState.Normal);
               uiBarBtn.CustomView = uiButton;

11.            NavigationController.TopViewController.
                  NavigationItem.RightBarButtonItem =
                     uiBarBtn;
            }

         }
      }
   }

Line 1 indicates this is a page renderer defined for the page of type ‘CustomNotificationIndicatorPage.” In Lines 6-9, the page Element is retrieved and assigns the implementation method for the “ToolbarNotificationChangedEvent” event. Line 10 defines the implementation of the event. It gets the CustomView of the RightBarButtonItem button and sets it title to the updated count value and assigns the button to the RightBarButtonItem. This reflects the updated count value on the toolbar.

To display an image and a text on the toolbar, we need to add another class file that inherits from the NavigationRenderer. Add a new class file and name it “NavRenderer.cs.” The code in the Navigation renderer is as follows:

 1. [assembly: ExportRenderer(typeof(NavigationPage),
       typeof(NavRenderer))]
 2. namespace CustomNotificationIndicator.iOS
 3. {
 4.    public class NavRenderer: NavigationRenderer
       {
 5.       public override void PushViewController
             (UIViewController viewController, bool animated)
          {
             base.PushViewController(viewController, animated);
 6.          if (TopViewController.NavigationItem.
                RightBarButtonItem != null)
             {
 7.             var uibutton = new UIButton();
                var rghtBarBtn = TopViewController.NavigationItem.
                   RightBarButtonItem;
                var image = UIImage.FromFile("icon-email.png");
                uibutton = UIButton.FromType(UIButtonType.Custom);
                uibutton.Font = UIFont.SystemFontOfSize(12);
 8.             uibutton.SetBackgroundImage(image, UIControlState.Normal);
 9.             uibutton.TitleEdgeInsets = new UIEdgeInsets(5, 5, 20, 2);
10.             uibutton.SetTitle(rghtBarBtn.Title, UIControlState.Normal);
11.             uibutton.Frame = new RectangleF(0, 0, 28, 20);
12.             uibutton.AddTarget(rghtBarBtn.Target, rghtBarBtn.Action,
                   UIControlEvent.TouchUpInside);
13.             var uiBarButton = new UIBarButtonItem(uibutton);

14.             TopViewController.NavigationItem.RightBarButtonItem =
                   uiBarButton;

             }
          }
       }
    }

Line 1 declares this page as a renderer of type Navigation Page. In Line 4, the page is inherited from NavigationRenderer. In Line 5, PushViewController method is overridden. In Line 6, we retrieve the RightBarButtonItem. Line 8 sets the background image of the button created in Line 7. Line 9 positions the title to be displayed. Line 10 sets the title of the button. Line 11 sets the height and width of the button. Line 12 assigns the events to the button. Line 13 creates the button of type UIBarButtonItem and, then, in Line 13 it assigns the button to the toolbar.

This finally displays a button with text on the top.

Summary

In this article, we saw how to add text over the button, a common scenario to display number of unread notifications/email or number of items in the cart. It also talks about how to communicate between a page model, code behind, and the renderers.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read