In einem aktuellen Projekt besteht die Anforderung eine mehrere Ebenen tiefe Navigation mit entsprechenden Unterebenen für die Navigation umzusetzen. Da es sich um eine iPad-App handelt, bietet sich für die Navigation der UISplitViewController mit entsprechenden UINavigationController für den Master, die linke Seite, und die Details, die rechte Seite, an.
Ich bin dabei auf das Problem gestoßen, dass beim Wechsel der Detailansichten der Hinweise auf das Menü im Portrait-Modus verschwindet. Nachfolgend möchte ich beschreiben, wie ich das Problem lösen konnte.
Innerhalb von FinishedLaunching
wird der SplitViewController instanziiert und dem Window als RootViewController zugewiesen.
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;
Weil im Portrait-Mode die linke Navigation, der sogenannte Master, ausgeblendet wird, ist für den Benutzer der App nicht sofort erkenntlich, dass er weitere Funktionen darüber erreichen kann. Wie hilfreich wäre es da, wenn die App einen entsprechen Hinweise einblenden würde?
Mit wenig Aufwand lässt sich das sehr schnell realisieren. Es muss lediglich die Delegate-Property des SplitViewControllers genutzt werden.
Dazu erstellen wir uns eine eigene UISplitViewDelegate-Implementierung.
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);
}
}
Fehlen noch die Controller für Master und Detailansicht. Ihr findet sie im Repository zu dieser App. An dieser Stelle möchte ich lediglich zeigen wie die Detailansicht entsprechend der Auswahl im Master ausgetauscht wird. Dazu betrachten wir die RowSelected
-Methode der entsprechenden 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;
}
}
Die App kann nun zu verschiedene Ebenen verschiedene Detailansichten bereitstellen. Man könnte jetzt zufrieden sein, würde nicht der Menü-Hinweis bei jedem Wechsel der Detailansicht verschwinden und erst mit einem Wechsel zur horizontalen und wieder zurück zur Portrait-Ansicht sichtbar werden.
Die Lösung hat mich ein bisschen Zeit gekostet, denn laut Dokumentation ist der SplitViewControllerDelegate zum Einblenden des Menüs sowie des Hinweises verantwortlich. Das besondere ist, dass er tatsächlich nur beim Wechsel zwischen Portrait und horizontaler Ansicht ausgelöst wird. Hinzu kommt, dass wir beim Wechsel der Detailansicht die komplette Hierarchie austauschen. Das wiederum ist notwendig, weil sich der RootController eines UINavigationControllers nicht austauschen lässt. Zu diesem Zeitpunkt verlieren wir den Hinweis.
Mit einer kleinen Modifikation im SplitViewDelegate und in der RowSelected Methode lässt sich das Problem beheben.
Die Implementierung des Delegates wird um eine UIBarButtonItem-Property erweitert.
public UIBarButtonItem BarButtonItem
{
get;
private set;
}
Die WillHideViewController-Methode wird um die Zeile BarButtonItem = barButtonItem;
erweitert um die Property zu setzen.
[Export("splitViewController:willHideViewController:withBarButtonItem:forPopoverController:")]
public void WillHideViewController(UISplitViewController splitController, UIViewController viewController, UIBarButtonItem barButtonItem, UIPopoverController popoverController)
{
...
BarButtonItem = barButtonItem;
}
In den TableViewSourcen greifen wir auf die Property zu und fügen so den Hinweistext einfach unseren neuen Detailansichten hinzu.
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;
}
}
Das war es auch schon. Der Code als ganzes steht auf GitHub zur Verfügung. Es ist ein funktionierendes Beispiel wie man ein UISplitViewController mit mehreren Master und Detailansichten verwenden kann.
Als Mobile-Enthusiast und Geschäftsführer der Cayas Software GmbH ist es mir ein großes Anliegen, mein Team und unsere Kunden zu unterstützen, neue potenziale zu entdecken und gemeinsam zu wachsen. Hier schreibe ich vor allem zur Entwicklung von Android und iOS-Apps mit Xamarin und .NET MAUI.
Like what you read? Come work with us.
Learn in 5 simple steps how Bluetooth and the External Accessory Framework play together to control a BeeWi car with Xamarin iOS.
Das Jahr 2013 endete mit einem großen Knall. Neben dem typischen Silvester-Feuerwerk gab es für mich und viele andere noch eine E-Mail aus Cupertino, die gerade für Januar einiges an Arbeit bedeuten konnte. Die Ankündigung von Apple ab dem 01.02.2014 nur noch Apps in den App-Store zu lassen, die iOS 7 konform sind war schon erstaunlich. Nicht wegen der Ankündigung an sich, sondern vielmehr wegen dem kurzen Zeitraum.