2014-09-26 4 views
11

Nel mio UISplitViewController, la vista principale è un UINavigationController contenente un UITableViewController. A volte, quando l'utente seleziona un elemento nella tabella, devo inserire un'altra tabellaViewController sulla tabella esistente nella vista principale.Avere un UINavigationController nella vista principale di un UISplitViewController in iOS 8

In iOS 7, dentro la mia prima UITableViewController mi basta chiamare

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

In iOS 8:

Quando la visualizzazione di divisione è compressa, l'otherTableVC diventa dettaglio View! Poi, dopo la rotazione del dispositivo, vediamo il lato due tabelle fianco ...

Peggio ancora, se il dispositivo mostra i due pannelli, il codice funziona grande e la seconda tabella viene spinta sopra il primo nella visualizzazione schema . Ma, dopo una doppia rotazione, i due tavoli sono di nuovo uno di fianco all'altro. Sembra che la modalità compressa di UISplitViewController interferisca con il mio controller di navigazione ...

Come posso gestire il mio UINavigationController nella Vista Master?

Grazie

Modificato:

mie entrambe le viste primarie e dettagli hanno un controller di navigazione. E per risolvere il mio problema, ho appena scoperto che, in modalità compressa, devo creare un controller di navigazione aggiuntivo e spostarlo sul controller di navigazione principale.

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

cappello Così ho appena scoperto che possiamo spingere un controller di navigazione all'interno di un altro controller di navigazione.

risposta

23

Risposta breve, è possibile controllare questo comportamento tramite i metodi UISplitViewControllerDelegate:

splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: 
splitViewController:separateSecondaryViewControllerFromPrimaryViewController: 

Ho il sospetto che ciò che si vuole veramente fare è affare con la situazione in cui si dispone di un app per iOS 8 UISplitViewController-based in cui il vostro primario e le viste dettagliate sono sia UINavigationControllers sia alcuni viewControllers (all'interno di questi controller di navigazione) che si desidera visualizzare solo sul lato principale o sul lato dettagli della visualizzazione divisa. La risposta qui sotto riguarda questo. Affronta anche la situazione in cui a volte desideri una vista per sostituire le visualizzazioni nel controller di navigazione Dettagli, piuttosto che essere spinto lì.

Un piccolo avvertimento: il codice qui sotto non si occupa di tutti i casi possibili e ha alcune ipotesi:

  • Non ci aspettiamo nulla può cambiare sullo stack controller di navigazione dettagliata quando la vista divisione è crollato e quelle viste sono oscurate da una vista dettagliata sopra di loro.
  • nostro UIViewController sottoclassi sono tutte dotate di shouldDisplayInDetailedView e proprietà shouldReplaceDetailedView
  • Partiamo dal presupposto che abbiamo solo spingere viste sul controller di navigazione dettagliato che ha l'insieme di proprietà shouldDisplayInDetailedView.
  • I controller di vista vengono aggiunti al lato Dettaglio tramite splitViewController: showDetailViewController: o pushViewController: animated: nella proprietà navigationController di una vista all'interno di una vista dettagliata (in stato espanso o compresso).
  • Visualizza i controllori che dovrebbero sostituire i controller di vista del controller di navigazione Particolare vengono aggiunti solo tramite splitViewController: showDetailViewController: e solo dall'interazione con vista nel controller della vista primaria, vale a dire, questo può avvenire solo se il controller della vista primaria è non oscurato quando è collassato.
  • Abbiamo un BlankViewController da visualizzare nella vista dettagli quando il controller della vista divisa viene espanso ma abbiamo solo controller di vista che dovrebbero rimanere sul lato primario.

Non consiglio attuazione solo lato della splitViewController: collapseSecondaryViewController: ontoPrimaryViewController:/splitViewController: separateSecondaryViewControllerFromPrimaryViewController: logica e seconda l'implementazione predefinita per l'altro lato. Apple fa alcune cose strane come mettere UINavigationViewController dal lato Detail nel lato primario come uno dei viewControllers nello stack del controller di navigazione primario, ma poi spingere altri controller di visualizzazione sopra di esso, che anche se si capisce completamente non può essere replicato da il tuo codice. Quindi è meglio gestire da soli entrambi i lati del processo.

Questo è quello che uso:

#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

Grazie mille Michael. In effetti, abbiamo solo un sacco di lavoro per gestire la nuova modalità "crollo". Penso che Apple abbia fatto qui una decisione molto povera. Perché non mantenere lo stesso principio di un popup (come l'iPad in modalità verticale)! – PatrickV

+0

Questo mi ha salvato la pancetta. Ho riscontrato problemi con iOS 9 e la funzionalità di multitasking. La specifica manuale di tutte queste cose ha davvero aiutato! – Hackmodford

+0

Anche io sto lottando con lo stesso problema. Uno di voi può caricare un piccolo progetto con la configurazione menzionata. Ho provato a convertire in Swift e se ho impostato shouldDisplayInDetailedView nel mio controller di visualizzazione dei dettagli, ricevo il messaggio 'Spingi un controller di navigazione non è supportato'. – Meanteacher