Load idiom-specific Storyboard in Xamarin.iOS with MvvmCross

Denys Fiediaiev
4 min readDec 6, 2020

--

I was prompted to write this post about a universal storyboard layout in Xamarin.iOS by the issue at the MvvmCross repository. It turned out there was a question about displaying different Storyboards bound to one ViewModel, so I decided to describe my experience in solving this problem.

Apple’s recommended way of using SizeClass is not enough when we need entirely different UI/UX for the iPad and iPhone, and the most straightforward way to achieve it is to use different Storyboards with a single ViewModel.

This post will describe how to teach the MvvmCross framework to load a View Controller from an idiom-specific Storyboard using a simple Xamarin.iOS app that renders a different UI on the iPhone and iPad.

But what exactly is a Storyboard? According to the official Xamarin tutorial, a Storyboard is the visual representation of all the screens in an application. It contains a sequence of scenes, with each scene representing a ViewController and its Views.

In our example, we use a small ViewModel with a text property to demonstrate that bindings are still working:

Demo ViewModel source code.

And that’s all about the ViewModels, so let’s move on to the View part.

First of all, MvvmCross supports loading view controllers from Storyboards by applying MvxFromStoryboardAttribute to the UIViewController-based class:

We are going to extend this feature to load different Storyboards, using a name convention for the storyboard files:

  • {StoryboardName}.Phone.storyboard for iPhone-specific Storyboards
  • {StoryboardName}.Pad.storyboard for iPad-specific Storyboards

The {StoryboardName} is the name we pass to the MvxFromStoryboard attribute.

Storyboard creation in Rider IDE.

Let’s create a first Storyboard and the ViewController for our demo app. In Rider IDE, it could be done by clicking on the project and selecting the Add menu. This one will be an iPhone Storyboard, so we will name it Storyboard.Phone.storyboard.

Then, we add a needed ViewController, implement the UI, add constraints, and ensure that the ViewController file is created and outlets are bound.

The storyboard for iPhone.

To create the iPad-specific Storyboard, we can copy the existing Storyboard.Phone.storyboard, rename it to Storyboard.Pad.storyboard, and update the UI accordingly.

The storyboard for iPad.

The ViewController file will not be generated, as we already generated this file with iPhone Storyboard. In other words: we have a 2 to 1 relationship between the Storyboard files and the ViewController file.

Here is the source code of the ViewController class:

Demo ViewController source code.

Please pay attention to the MvxFromStoryboard
attribute: it tells MvvmCross the name of the Storyboard from which to load the ViewController.

In the existing implementation, MvvmCross will load the Storyboard.storyboard file, but we need to load either Storyboard.Phone.storyboard, or Storyboard.Pad.storyboard.

To intercept the View creation process, we need a custom MvxIosViewsContainer implementation:

The new implementation of MvxIosViewsContainer.

This custom container checks the idiom of the current interface and tries to load the Storyboard according to the file naming convention we applied earlier. If there is no Storyboard for a specific idiom, the default Storyboard will be loaded.

And the last thing we need to do is to register the container in the Setup class:

Container registration source code.

Finally, our demo app can present different UI on iPad and iPhone:

--

--

Denys Fiediaiev
Denys Fiediaiev

Written by Denys Fiediaiev

Xamarin | iOS | Android Developer with 8 years of experience. All things actionable tips, real-life examples and coding guides to help you grow professionally.

No responses yet