Tab navigation for Xamarin.iOS using MvvmCross
This post is a part of #XamarinUIJuly. Check out all the other posts here!
Tabs are an extremely common navigation pattern in mobile applications. Some of the most popular and widely used mobile application feature tab-based navigation (WhatsApp, Facebook, Instagram, Messenger to name a few)
This post will walkthrough how to implement tab-based navigation in Xamarin.iOS using MvvmCross, a robust cross-platform MVVM framework.
We will implement tabs similar to the one seen in the Facebook application.
Notes
- This walkthrough will show how to setup a brand new MvvmCross project from scratch for tab navigation, however, specific details about setting up MvvmCross are beyond the scope of this walkthrough.
- We want to be able to perform nested navigation within each tab
Step 1: Solution Setup
We will start by setting up our MvvmCross solution. In Visual Studio, through the new project wizard choose the Blank Native App (iOS, Android) template. Complete the wizard leaving everything else as is.
Once the new project is created, delete the portable class library project and replace it with a .Net Standard Library project. We will refer to this as the Core project.
Finally, delete the StoryBoard file from the iOS project and clear out the Main Interface setting in the Info.plist file.
Step 2: MvvmCross Setup
Now that we have a nice clean solution setup, lets add MvvmCross. We will start by installing the MvvmCross Nuget package into our iOS project and the Core project.
Now that we have all the packages installed, let’s setup our app to use MvvmCross.
In the Core project, create two files App.cs
and TabsViewModel.cs
:
//TabsViewModel.cs
public class TabsViewModel : MvxViewModel
{
public TabsViewModel(){ }
}//App.cs
public class App : MvxApplication
{
public App()
{
}
public override void Initialize()
{
base.Initialize(); //Tell MvvmCross to show this ViewModel first
RegisterAppStart<TabsViewModel>();
}
}
Now that we have that setup, we need to setup our iOS project. We will come back and modify our TabsViewModel
later.
Modify the existing AppDelegate.cs
file as below:
[Register("AppDelegate")]
public class AppDelegate : MvxApplicationDelegate<MvxIosSetup<App>, App>
{
}
Next, create a TabsViewController
class that inherits from MvxTabBarViewController
:
[MvxRootPresentation(WrapInNavigationController=false)]
public class TabsViewController : MvxTabBarViewController<TabsViewModel>
{
public TabsViewController()
{
} public override void ViewDidLoad()
{
base.ViewDidLoad();
}
}
Notice that the ViewController is decorated with the following attribute:[MvxRootPresentation(WrapInNavigationController=false)]
.
We are now ready to start setting up our tabs!
Step 3: Setup Tabs
The Facebook app has 5 tabs; we need to create ViewModels to represent each one of these tabs. We will create the ViewModels as such:
- News Feed —
NewsFeedViewModel
- Requests —
RequestsViewModel
- Messages —
MessagesViewModel
- Notification —
NotificationsViewModel
- More —
MoreViewModel
public class NewsFeedViewModel : MvxViewModel
{
}
public class RequestsViewModel : MvxViewModel
{
}
public class MessagesViewModel : MvxViewModel
{
}
public class NotificationsViewModel : MvxViewModel
{
}
public class MoreViewModel : MvxViewModel
{
}
Now that we have our ViewModels setup, we need to modify our TabsViewModel
from earlier and expose a method to Setup these tabs. Modify the TabsViewModel
to looks like below:
public class TabsViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;public TabsViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}public Task SetupTabs()
{
return Task.WhenAll(
_navigationService.Navigate(typeof(NewsFeedViewModel)),
_navigationService.Navigate(typeof(RequestsViewModel)),
_navigationService.Navigate(typeof(MessagesViewModel)),
_navigationService.Navigate(typeof(NotificationsViewModel)),
_navigationService.Navigate(typeof(MoreViewModel)
));
}
}
We have done a few things here:
- We use the built-in dependency injection in MvvmCross to obtain a reference to the MvxNavigationService
- We expose a method that calls
Navigate
on the MvxNavigationService for each of our individual Tabs
Thats all the code we need in the Core project. We can now move on to the iOS project and finish setting up our tabs
On iOS, implement a ViewController for each of the above ViewModels. Decorate each ViewController with an [MvxTabPresentation]
attribute. Here is the NewsFeedViewController
as an example:
[MvxTabPresentation(TabName = "News Feed", TabIconName = "unselected", TabSelectedIconName = "selected", WrapInNavigationController = true)]
public class NewsFeedViewController : MvxViewController<NewsFeedViewModel>
{
public override void ViewDidLoad()
{
base.ViewDidLoad();View.BackgroundColor = UIColor.Red;
NavigationItem.Title = "News Feed";
}
}
Note that the [MvxTabPresentation]
attribute has it’s WrapInNavigationController
property set to true
. This wraps each tab ViewController in a UINavigationController, allowing nested navigation within each tab.
Now that all the individual ViewControllers for each tab are setup, we have just one last thing left to do to complete our iOS implementation. Remember that SetupTabs
method we implemented in TabsViewModel
? We need to call that from our TabsViewController
.
Modify the TabsViewController
as shown below:
[MvxRootPresentationAttribute(WrapInNavigationController = false)]
public class TabsViewController : MvxTabBarViewController<TabsViewModel>
{
private bool _tabsInitialized;public TabsViewController()
{
}public override void ViewDidLoad()
{
base.ViewDidLoad();
}public override async void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);if (!_tabsInitialized) {
await ViewModel.SetupTabs();
_tabsInitialized = true;
}
}
}
We override the ViewWillAppear
lifecycle method and call our SetupTabs
method, making sure its only ever called once.
So what is going on behind the covers?
When we call SetupTabs
from our ViewController, the request is routed to the built-in MvvmCross iOS View Presenter which tells the MvxTabBarViewController
to create and add the tab to the tab bar.
Check out the implementation of ShowTabViewController
method in the MvxIosViewPresenter
.
Thats it! iOS is complete! Build and run your app to see the tabs!
Part 2 Tab navigation for Xamarin.Android using MvvmCross coming soon!
Thanks for reading! Grab the code on GitHub.