2014-09-26 6 views
11

In meinem UISplitViewController ist die Masteransicht ein UINavigationController, der einen UITableViewController enthält. Irgendwann, wenn der Benutzer ein Element in der Tabelle auswählt, muss ich einen anderen TableViewController über die vorhandene Tabelle in der Masteransicht schieben.Ein UINavigationController in der Masteransicht eines UISplitViewControllers in iOS 8

In iOS 7, in meinem ersten UITableViewController nenne ich

nur
[self.navigationController pushViewController:otherTableVC animated:YES]; 

In iOS 8:

Wenn die geteilte Ansicht kollabiert ist, die otherTableVC das Detail wird! Dann, nachdem das Gerät dreht, sehen wir die zwei Tabellen nebeneinander ...

Schlimmer noch, wenn das Gerät die beiden Scheiben zeigt, der Code funktioniert super und die zweite Tabelle wird über die erste in der Masteransicht geschoben . Aber nach einer doppelten Drehung sind die beiden Tische wieder nebeneinander. Es scheint, dass der minimierte Modus des UISplitViewController mit meinem eigenen Navigationscontroller kollidiert ...

Wie kann ich meinen eigenen UINavigationController in der Masteransicht verwalten?

Danke

EDITED:

Meine primäre und Details Ansichten, die eine Navigation-Controller haben. Und um mein Problem zu lösen, habe ich gerade entdeckt, dass ich im kollabierten Modus einen zusätzlichen Navigations-Controller erstellen und ihn über den primären Navigations-Controller schieben muss.

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:otherTableVC]; 
[self.navigationController pushViewController:navController animated:YES]; 

Also habe ich gerade entdeckt, dass wir einen Navigationscontroller in einen anderen Navigationscontroller schieben können.

Antwort

23

Kurze Antwort, Sie dieses Verhalten über die UISplitViewControllerDelegate Methoden steuern:

splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: 
splitViewController:separateSecondaryViewControllerFromPrimaryViewController: 

Ich vermute, was Sie wirklich tun möchte, ist befassen sich mit der Situation, in der Sie ein iOS 8 UISplitViewController-basierte Anwendung, wo Ihre primäre und detaillierte Ansichten sind beide UINavigationControllers und es gibt einige viewControllers (innerhalb dieser Navigationssteuerungen), die nur auf der primären oder Detailseite der geteilten Ansicht erscheinen sollen. Die folgende Antwort befasst sich damit. Es wird auch mit der Situation fertig, in der Sie manchmal möchten, dass eine Ansicht die Ansichten im Detail-Navigationscontroller ersetzt, anstatt dass sie dorthin geschoben wird.

Ein kleiner Nachteil: der folgende Code nicht mit allen möglichen Fällen befassen und einige Annahmen hat:

  • Wir erwarten nicht, alles kann auf dem Detailnavigationscontroller Stapel verändern, wenn die geteilte Ansicht kollabiert ist und diese Ansichten werden durch eine Detailansicht über ihnen verdeckt.
  • Unsere UIViewController Unterklassen haben alle eine shouldDisplayInDetailedView und shouldReplaceDetailedView Eigenschaft
  • Wir gehen davon aus, dass wir nur Blick auf die detaillierte Navigationssteuerung drücken, die die shouldDisplayInDetailedView Eigenschaft festgelegt haben.
  • View-Controller werden über splitViewController zur Detailseite hinzugefügt: showDetailViewController: oder pushViewController: animiert: in der navigationController-Eigenschaft einer View in einer Detailansicht (im maximierten oder im komprimierten Zustand).
  • View Controller, die ersetzen sollten die View-Controller in der Detail Navigation Controller werden nur über SplitViewController: ShowDetailViewController: und nur von Interaktion mit Sicht in der primären Ansicht Controller, dh kann dies nur passieren, wenn der primäre View-Controller ist im kollabierten Zustand nicht verdeckt.
  • Wir haben einen BlankViewController, der in der Detailansicht angezeigt wird, wenn der Split-View-Controller erweitert wird, aber wir nur View-Controller haben, die auf der Primärseite bleiben sollen.

Ich empfehle nicht nur eine Seite der splitViewController Umsetzung: collapseSecondaryViewController: ontoPrimaryViewController:/splitViewController: separateSecondaryViewControllerFromPrimaryViewController: Logik und in Abhängigkeit von der Standardimplementierung für die andere Seite. Apple macht einige seltsame Dinge, wie den UINavigationViewController von der Detailseite in die primäre Seite als einen der viewControllers im primären Navigations-Controller-Stack zu setzen, aber dann andere View-Controller darüber zu schieben, was selbst dann nicht repliziert werden kann, wenn man alles noch versteht Dein eigener Code. Daher ist es am besten, beide Seiten des Prozesses selbst zu behandeln. Diese

ist das, was ich benutze:

#pragma mark - 
#pragma mark Split View Controller delegate. 

- (BOOL)splitViewController:(UISplitViewController *)splitViewController showViewController:(UIViewController *)vc sender:(id)sender 
{ 
    //Standard behaviour. This won't get called in our case when the split view is collapsed and the primary view controllers are obscured. 
    return NO; 
} 

// Since we treat warnings as errors, silence warning about unknown selector below on UIViewController subclasses. 
#pragma GCC diagnostic ignored "-Wundeclared-selector" 


- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)vc sender:(id)sender 
{ 
    if (splitViewController.collapsed == NO) 
    { 
     // The navigation controller we'll be adding the view controller vc to. 
     UINavigationController *navController = splitViewController.viewControllers[1]; 

     UIViewController *topDetailViewController = [navController.viewControllers lastObject]; 
     if ([topDetailViewController isKindOfClass:[BlankViewController class]] || 
      ([vc respondsToSelector:@selector(shouldReplaceDetailedView)] && [vc performSelector:@selector(shouldReplaceDetailedView)])) 
     { 
      // Replace the (expanded) detail view with this new view controller. 
      [navController setViewControllers:@[vc] animated:NO]; 
     } 
     else 
     { 
      // Otherwise, just push. 
      [navController pushViewController:vc animated:YES]; 
     } 
    } 
    else 
    { 
     // Collapsed. Just push onto the conbined primary and detailed navigation controller. 
     UINavigationController *navController = splitViewController.viewControllers[0]; 
     [navController pushViewController:vc animated:YES]; 
    } 

    // We've handled this ourselves. 
    return YES; 
} 

- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController 
{ 
    UINavigationController *primaryNavController = (UINavigationController *)primaryViewController; 
    UINavigationController *secondaryNavController = (UINavigationController *)secondaryViewController; 
    UIViewController *bottomSecondaryView = [secondaryNavController.viewControllers firstObject]; 
    if ([bottomSecondaryView isKindOfClass:[BlankViewController class]]) 
    { 
     NSAssert([secondaryNavController.viewControllers count] == 1, @"BlankViewController is not only detail view controller"); 
     // If our secondary controller is blank, do the collapse ourself by doing nothing. 
     return YES; 
    } 

    // We need to shift these view controllers ourselves. 
    // This should be the primary views and then the detailed views on top. 
    // Otherwise the UISplitViewController does wacky things like embedding a UINavigationController inside another UINavigation Controller, which causes problems for us later. 
    NSMutableArray *newPrimaryViewControllers = [NSMutableArray arrayWithArray:primaryNavController.viewControllers]; 
    [newPrimaryViewControllers addObjectsFromArray:secondaryNavController.viewControllers]; 
    primaryNavController.viewControllers = newPrimaryViewControllers; 

    return YES; 
} 

- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController 
{ 
    UINavigationController *primaryNavController = (UINavigationController *)primaryViewController; 

    // Split up the combined primary and detail navigation controller in their component primary and detail view controller lists, but with same ordering. 
    NSMutableArray *newPrimaryViewControllers = [NSMutableArray array]; 
    NSMutableArray *newDetailViewControllers = [NSMutableArray array]; 
    for (UIViewController *controller in primaryNavController.viewControllers) 
    { 
     if ([controller respondsToSelector:@selector(shouldDisplayInDetailedView)] && [controller performSelector:@selector(shouldDisplayInDetailedView)]) 
     { 
      [newDetailViewControllers addObject:controller]; 
     } 
     else 
     { 
      [newPrimaryViewControllers addObject:controller]; 
     } 
    } 

    if (newDetailViewControllers.count == 0) 
    { 
     // If there's no detailed views on the top of the navigation stack, return a blank view (in navigation controller) for detailed side. 
     UINavigationController *blankDetailNavController = [[UINavigationController alloc] initWithRootViewController:[[BlankViewController alloc] init]]; 
     return blankDetailNavController; 
    } 

    // Set the new primary views. 
    primaryNavController.viewControllers = newPrimaryViewControllers; 

    // Return the new detail navigation controller and views. 
    UINavigationController *detailNavController = [[UINavigationController alloc] init]; 
    detailNavController.viewControllers = newDetailViewControllers; 
    return detailNavController; 
} 
+1

Sie sehr viel Michael danken. In der Tat haben wir nur eine Menge Arbeit, um den neuen "Kollaps" -Modus zu bewältigen. Ich denke, Apple hat hier eine sehr schlechte Entscheidung getroffen. Warum nicht das Prinzip eines Popups beibehalten (wie das iPad im Hochformat)! – PatrickV

+0

Das hat meinen Speck gerettet. Ich hatte Probleme mit iOS 9 und der Multitasking-Funktion. All das manuell zu spezifizieren, hat wirklich geholfen! – Hackmodford

+0

Ich kämpfe auch mit dem gleichen Problem. Kann einer von Ihnen ein kleines Projekt mit dem erwähnten Setup hochladen? Ich habe versucht, zu Swift zu konvertieren, und wenn ich in meinem Detailansicht-Controller sumoDisplayInDetailedView einstelle, bekomme ich die Meldung "Pushing a navigation controller is not supported". – Meanteacher

Verwandte Themen