While implementing this, I ran into the problem that the menu hint disappears in portrait mode whenever the detail view is changed. Below I would like to describe how I solved that problem.
Creating the prerequisites
Inside FinishedLaunching, the SplitViewController is instantiated and assigned to the window as the root view controller.
var splitViewController = new UISplitViewController();
splitViewController.Delegate = new SplitViewControllerDelegate();
var detailViewController = new UIViewController();
var navigationRootController = new MainNavigationController();
splitViewController.ViewControllers = new UIViewController[]{ new UINavigationController(navigationRootController), new UINavigationController(detailViewController) };
...
window.RootViewController = splitViewController;
Because the left-hand navigation, the so-called master, is hidden in portrait mode, users do not immediately realize that they can access further functions from there. How useful would it be if the app displayed a corresponding hint?
This can be implemented very quickly with little effort. You only need to use the Delegate property of the SplitViewController.
For that, create your own UISplitViewDelegate implementation.
class SplitViewControllerDelegate : UISplitViewControllerDelegate
{
public override bool ShouldHideViewController(UISplitViewController svc, UIViewController viewController, UIInterfaceOrientation inOrientation)
{
return inOrientation == UIInterfaceOrientation.Portrait || inOrientation == UIInterfaceOrientation.PortraitUpsideDown;
}
[Export("splitViewController:willHideViewController:withBarButtonItem:forPopoverController:")]
public void WillHideViewController(UISplitViewController splitController, UIViewController viewController, UIBarButtonItem barButtonItem, UIPopoverController popoverController)
{
barButtonItem.Title = viewController.Title;
var detailNavController = splitController.ViewControllers[1] as UINavigationController;
var detailViewController = detailNavController.TopViewController;
detailViewController.NavigationItem.SetLeftBarButtonItem(barButtonItem, true);
}
[Export("splitViewController:willShowViewController:invalidatingBarButtonItem:")]
public void WillShowViewController(UISplitViewController svc, UIViewController vc, UIBarButtonItem button)
{
svc.ChildViewControllers[1].ChildViewControllers[0].NavigationItem.SetLeftBarButtonItem(null, true);
}
}
The controllers for master and detail view are still missing. You can find them in the repository for this app. Here I only want to show how the detail view is replaced based on the selection in the master. For that, we look at the RowSelected method in the corresponding TableViewSource.
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
switch (indexPath.Row)
{
case 0:
var demoCtrl1 = new DemoController1();
parentController.SplitViewController.ViewControllers = new UIViewController[]{ parentController.SplitViewController.ViewControllers[0], new UINavigationController(demoCtrl1) };
break;
case 1:
var demoCtrl2 = new DemoController2();
parentController.SplitViewController.ViewControllers = new UIViewController[]{ parentController.SplitViewController.ViewControllers[0], new UINavigationController(demoCtrl2) };
break;
}
}
The problem
The app can now provide different detail views for different levels. At that point, one could be satisfied if it were not for the fact that the menu hint disappears every time the detail view is changed and only reappears after switching to landscape and back to portrait mode.
The solution
The solution cost me a little time because, according to the documentation, the SplitViewControllerDelegate is responsible for showing the menu and the corresponding hint. The special thing is that it is actually triggered only when switching between portrait and landscape. On top of that, when we change the detail view we replace the entire hierarchy. That is necessary because the root controller of a UINavigationController cannot be exchanged. At that point, we lose the hint.
With a small modification in SplitViewDelegate and in the RowSelected method, the problem can be fixed.
Extending SplitViewDelegate
The delegate implementation is extended by a UIBarButtonItem property.
public UIBarButtonItem BarButtonItem
{
get;
private set;
}
WillHideViewController is extended by the line BarButtonItem = barButtonItem; to set that property.
[Export("splitViewController:willHideViewController:withBarButtonItem:forPopoverController:")]
public void WillHideViewController(UISplitViewController splitController, UIViewController viewController, UIBarButtonItem barButtonItem, UIPopoverController popoverController)
{
...
BarButtonItem = barButtonItem;
}
Adjusting the TableViewSource
In the TableViewSource, we access this property and simply attach the hint button to the new detail views.
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
var barButtonItem = (parentController.SplitViewController.Delegate as SplitViewControllerDelegate).BarButtonItem;
switch (indexPath.Row)
{
case 1:
var customerData = new CustomerDataController();
if (barButtonItem != null)
customerData.NavigationItem.SetLeftBarButtonItem(barButtonItem, false);
parentController.SplitViewController.ViewControllers = new UIViewController[]{ parentController.SplitViewController.ViewControllers[0], new UINavigationController(customerData) };
break;
case 0:
var userInfo = new UserInformationController();
if (barButtonItem != null)
userInfo.NavigationItem.SetLeftBarButtonItem(barButtonItem, false);
parentController.SplitViewController.ViewControllers = new UIViewController[]{ parentController.SplitViewController.ViewControllers[0], new UINavigationController(userInfo) };
break;
}
}
That is already enough. The complete code is available on GitHub. It is a working example of how to use a UISplitViewController with multiple master and detail views.
Sebastian Seidel
As a mobile enthusiast and managing director of Cayas Software GmbH, it is very important to me to support my team and our customers in discovering new potential and growing together. Here I mainly write about the development of Android and iOS apps with Xamarin and .NET MAUI.