More familiar tabs for your users in Xamarin.Forms
Amongst the great variety of out-of-the-box pages that Xamarin.Forms has to offer, we can choose a
TabbedPage wich is nothing else than a container to other pages, making them accesible trough tabs. You probable have used them and, as me, you think they are awesome, what it is not so awesome is the fact that they are somewhat limited as they do not allow so much customization.
That is why I decided to create a custom renderer that allows to further stylize the tabs, making them more native for your users.
After that, you need to create a page that inherits from
And as you usually do with a normal
TabbedPage, add the child pages in the constructor. It is very important that you note that the names do not end with “.png”, because otherwise your tabs will not work properly on iOS.
The we would get something like this (on the left is the same page but created with a common
Dowload the source code so you can see the run and play with the sample app for this post.
And that’s all… now, if you want to know how I managed to deliver this customization, keep on reading.
Among the things that I wanted to customize are the color of the selected item, the color of the unselected item, and when in iOS the icon of the selected element becuase as you may have seen in the previous gifs when using Android it is hard to tell at first sight in which page are we on, while in iOS it is a bit weird that the icon of the selected stays the same as the others.
Start by defining a class that inherits from the type of page that we are going to customize.
Then we define the properties, along with its correspondent
BindableProperty that will allow these properties to be bindable.
The property descriptions are the following:
SelectedColor: The color of the selected item
BarBackgroundColor: The background color of the bar, I decided to hide with
newthe default implementation, as I’m going to control the behavior of it inside the custom renderer.
BarBackgroundApplyTo: An enum that indicates in which platforms the backround color of the bar needs to be modified, the default is Android, as I consider that in iOS it seems a bit weird setting the background color of the bar.
Apart from that, I created some extension methods that are useful to work with colors, making them darker or lighter, or help deciding whether one color is light or dark.
Now, we are ready to see each platform implementation:
(this renderer is completely based on the implementation of James Montemagno in the Xamarin’s Evolve App)
In iOS we need to create a renderer that inherits from
After that I defined a property to access to the forms instance of
PlatformTabbedPage and another couple to store the default colors of the
If you have previously written a custom renderer you should know of the importance of the
OnElementChanged method, because it is called every time your control is going to be rendered on screen. That is why we assign and unassign an event that will allow us to know whent the properties of the bar in the forms project change.
Then we get and store the default colors of the
UITabBar just in case we need them in the future.
Once the original colors are stored, we call a couple of methods that will assign the desired colors.
Now it is time to “fill” the icons, and I say “fill” because in reality you need to provide a “filled” version of your icons, one is going to be shown by default while the oter is going to be displayed when the tab is active.
The trick here relies in the fact that the iOS API exposes a property to set an image for each state of a given tab, and that is precisely what this renderer does: takes the original icon, appends the suffix “_active” and sets it aas the image that should be used when the tab is selected:
And basically that’s all, we do not require of anything else thanks to the iOS API.
For the Android renderer we must derive from the
TabbedPageRenderer class, yes, we need a different renderer for Android.
Again, we need some properties to store the default colors:
In Android, a tabbed page is comprised by two elements: A
ViewPager and a
TabLayout that work together to act as a single control, given the importance for this renderer, we also need to store a class level reference to both elements:
Now, inside the
OnElementChanged method we are going to get the references to the Views declared before. The renderer contains both, but they’re “hidden” as
View types, that is why the
is operator is used to know which cast to use:
We get the default colors for the bar background and then we set our own colors:
Unlike iOS, Android makes use of a couple of methods that are called everytime a tab is selected/unselected, that is why we need to assign them inside our aforementioned method:
To finish overriding of this method, we need to set the color of all icons as unselected, and then mark the firs one as selected:
And to finish this masterpiece, here is the “magic”. In the methods that handle each selection/unselection of tabs we need to apply a color filter to each image, as you can see the color varies depending on the tab being selected or not:
And that’s it, the renderer for Android is slightly more complicated than the iOS one, but it isn’t hard to understand.