13

Sto avendo un UISplitViewController che contiene un UITabBarController come vista principale. Questo UITabBarController contiene un UINavigationController. La vista dettagli contiene anche un UINavigationController.UINavigationController all'interno di un UITabBarController all'interno di un UISplitViewController presentato modalmente su iPhone

Storyboard

Sul iPad funziona come previsto. Il dettaglio dello spettacolo segue presenta la visualizzazione di immagini all'interno del controller di navigazione nella vista di dettaglio.

Sull'iPhone, d'altra parte, mi aspettavo che il dettaglio dello spettacolo spinga la vista di dettaglio sullo stack del controller di navigazione della vista principale. Ma in realtà è presentato in modo modale sulla vista principale.

Quando si rimuove UITabBarController dallo storyboard e si utilizza UINavigationController direttamente nella vista principale, questo funziona.

Qualcuno ha idea di come presentare la vista di dettaglio sullo stack del master UINavigationController su un iPhone?

risposta

8

Ho scoperto come mettere il dettaglio sul master UINavigationController invece di presentarlo modicamente su UITabBarController.

Utilizzando il metodoUISplitViewControllerDelegate

- splitViewController:showDetailViewController:sender: 

Nel caso l'UISplitViewController è compressa ottenere il controllore master navigazione e spingere la vista dettagliata su questo controller di navigazione:

- (BOOL)splitViewController:(UISplitViewController *)splitViewController 
    showDetailViewController:(UIViewController *)vc 
        sender:(id)sender { 
    NSLog(@"UISplitViewController collapsed: %d", splitViewController.collapsed); 

    // TODO: add introspection 
    if (splitViewController.collapsed) { 
     UITabBarController *master = (UITabBarController *) splitViewController.viewControllers[0]; 
     UINavigationController *masterNavigationController = (UINavigationController *)master.selectedViewController; 

     // push detail view on the navigation controller 
     //[masterNavigationController pushViewController:vc animated:YES]; 
     // push was not always working (see discussion in answer below), use showViewController instead 
     [masterNavigationController showViewController:vc sender:sender]; 

     return YES; 
    } 

    return NO; 
} 
+0

Ho esattamente lo stesso storyboard e il problema, e la tua risposta mi ha avvicinato un po 'all'obiettivo. Tuttavia, splitViewController: showDetailViewController: sender: delegate viene attivato una sola volta per me ... i successivi "shows" non attivano il delegato. Cosa hai finito con l'assegnazione come delegato? – Fozzle

+0

Ulteriori indagini mostrano che il mio delegato splitView viene riassegnato dopo la navigazione. Se capisco perché aggiornerò. – Fozzle

+2

Questa soluzione non funzionerà per iPhone 6 +. Avvia la tua app in verticale, vai alla visualizzazione dei dettagli. Quindi passare al paesaggio, sia i dettagli che le viste principali mostreranno la vista di dettaglio. –

4

La risposta di @PeterOettl alla sua stessa domanda mi ha messo sulla strada giusta ed è fantastico per questo. Quindi il merito è di lui.

mi hanno quasi la stessa struttura storyboard come lui, ma come vc è una navigationController ottengo un errore di runtime dicendo

'Spingendo un controller di navigazione non è supportato'

Come detto, questo perché vc è il navigationController della vista di dettaglio e non il viewController della vista di dettaglio.

Nota che mi sorprende che @PeterOettl non ottenga quell'errore anche nel suo caso, poiché il passaggio indicato nell'immagine dello storyboard punta al controller di navigazione della vista di dettaglio.

Pertanto il codice desidero che (Swift) semplicemente aggiungendo

let detailViewControllerNavigationController = (vc as UINavigationController).viewControllers[0] as UIViewController 

e spingendo detailViewControllerNavigationController anziché vc

e l'intero codice è

func splitViewController(splitViewController: UISplitViewController, showDetailViewController vc: UIViewController, sender: AnyObject?) -> Bool { 
    println("UISplitViewController collapsed: \(splitViewController.collapsed)") 
    if (splitViewController.collapsed) { 
     let master = splitViewController.viewControllers[0] as UITabBarController 
     let masterNavigationController = master.selectedViewController as UINavigationController 

     let detailViewControllerNavigationController = (vc as UINavigationController).viewControllers[0] as UIViewController 

     masterNavigationController.pushViewController(detailViewControllerNavigationController, animated: true) 

     return true 
    } else { 
     return false 
    } 
} 

noti inoltre che questo codice viene inserito nello AppDelegate.swift dell'esempio master-detail di Xcode in cui viene aggiunta una barra delle schede nella vista principale.

EDIT

Nei commenti che abbiamo discusso con @PeterOettl della differenza tra .pushViewController e .showViewController.

documentazione Apple dice:

showViewController: mittente:

Questo metodo spinge un nuovo View Controller nello stack di navigazione in maniera simile a come la pushViewController: animato: metodo. È possibile chiamare questo metodo direttamente se lo si desidera, ma in genere questo metodo viene chiamato da altrove nella gerarchia del controller di visualizzazione quando è necessario visualizzare un nuovo controller di visualizzazione .

Disponibile in iOS 8.0 e versioni successive.

+1

Questo è davvero interessante! Quando ho scritto la mia soluzione sopra ho implementato solo i dettagli del dettaglio in alto della mia story board. Quando ho implementato il dettaglio dello show inferiore ora, ho ricevuto lo stesso errore ('Spingendo un controller di navigazione non è supportato') come hai fatto tu. Non ero in grado di capire le differenze tra quei due seguiti, ma il tuo suggerimento ha funzionato bene. Grazie per quello. Ad ogni modo, sarebbe davvero interessante scoprire perché funziona nei primi passi, ma non nel secondo. Se qualcuno ha un'idea per questo sarebbe fantastico. –

+1

invece di pushViewController ho usato il metodo showViewController. Questo funziona bene in entrambi i casi, anche se non sono ancora sicuro delle differenze poiché entrambe le volte spingevo un UINavigationController su un UINavigationController. Puoi provare se showViewController funziona anche nel tuo caso? –

+1

Ci scusiamo per il ritardo. Ho provato con .showViewController invece di .pushViewController e, come te, non vedo differenze. L'animazione sembra uguale e tutto sembra uguale. Mi chiedo se la parola frame identifica che mostra un controller di navigazione e quindi spinge automaticamente in mostra. – HpTerm

9

Il problema con la soluzione di Peter è che si romperà con l'iPhone 6 +. Come mai? Con quel codice, se un iPhone 6 + è orientato in verticale, la vista di dettaglio si sposta sulla pila di navigazione. Tutto va bene, finora. Ora, ruota in orizzontale, e poi vedrai la vista dettagliata come vista di dettaglio e la vista principale.

Avrete bisogno delegato del controller vista divisa per implementare due metodi:

- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)detailVC sender:(id)sender 
{ 
    UITabBarController *masterVC = splitViewController.viewControllers[0]; 

    if (splitViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) 
     [masterVC.selectedViewController showViewController:detailVC sender:sender]; 
    else 
     [splitViewController setViewControllers:@[masterVC, detailVC]]; 

    return YES; 
} 

E ora, è necessario restituire la vista del regolatore superiore dal controller di navigazione della scheda selezionata:

- (UIViewController*)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController 
{ 
    UITabBarController *masterVC = splitViewController.viewControllers[0]; 

    if ([(UINavigationController*)masterVC.selectedViewController viewControllers].count > 1) 
     return [(UINavigationController*)masterVC.selectedViewController popViewControllerAnimated:NO]; 
    else 
     return nil; // Use the default implementation 
} 

Con questa soluzione, tutto spinge lo stack di navigazione quando necessario e aggiorna anche la vista dettagliata correttamente sull'iPad/6 + orizzontale.

+0

Questo ha funzionato perfettamente per me. –

+0

L'implementazione di - (BOOL) splitViewController: (UISplitViewController *) splitViewController showDetailViewController: (UIViewController *) detailVC mittente: (id) il mittente sembra essere sufficiente per me. –

0

ho implementato @Dreaming In risposta di binario in Swift:

func splitViewController(splitViewController: UISplitViewController, showDetailViewController vc: UIViewController, sender: AnyObject?) -> Bool { 
    let masterVC = splitViewController.viewControllers[0] as UITabBarController 

    if splitViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Compact { 
     masterVC.selectedViewController?.showViewController(vc, sender: sender) 
    } else { 
     splitViewController.viewControllers = [masterVC, vc] 
    } 

    return true 
} 

func splitViewController(splitViewController: UISplitViewController, separateSecondaryViewControllerFromPrimaryViewController primaryViewController: UIViewController!) -> UIViewController? { 
    let masterVC = splitViewController.viewControllers[0] as UITabBarController 

    if let navController = masterVC.selectedViewController as? UINavigationController { 
     if navController.viewControllers.count > 1 { 
      return navController.popViewControllerAnimated(false) 
     } 
    } 
    return nil 
} 
0

apprezzo questa discussione quando mi stava realizzando esattamente la stessa struttura UI applicazione, e Furthurmore reso adattivo per iPhone 6 rotazione Plus e iPad multitasking (Slide Over/Split View, iOS 9 o successive).

Abbiamo messo la soluzione completa (UISplitViewController adattivo con UITabBarController come controller di visualizzazione principale) open source su GitHub indievox-inc/TabBarSplitViewController. Grazie!