2013-10-03 15 views
22

Lasciare ContainerView essere la vista contenitore padre con due viste di contenuto figlio: NavigationView e ContentView.Scambio di viste secondarie in una vista Contenitore

Example of View Layout

Vorrei poter scambiare controllore di ContentView con un'altra vista. Ad esempio, lo scambio di un controller di pagina iniziale con un controller di pagina di notizie. Attualmente, l'unico modo in cui posso pensare di farlo è quello di utilizzare un delegato per dire allo ContainerView che voglio cambiare vista. Questo sembra un modo sciatto per fare ciò perché lo finirebbe con un gruppo di delegati speciali per tutte le sottoview.

Anche questo deve comunicare con lo NavigationView che contiene informazioni su quale vista è attualmente nello ContentView. Ad esempio: se l'utente si trova nella pagina delle notizie, la barra di navigazione all'interno della visualizzazione di navigazione mostrerà che il pulsante delle notizie è attualmente selezionato.

Domanda A: C'è un modo per scambiare il controller in ContentView senza un metodo delegato chiamando il ContainerView stessa? Mi piacerebbe farlo a livello di programmazione (senza storyboard).

Domanda B: Come posso scambiare i controller in ContentView dal NavigationView senza bando delegato? Mi piacerebbe farlo a livello di programmazione (senza storyboard).

+2

Hai dato un'occhiata a UIPageViewController? "Un controller di visualizzazione di pagina consente all'utente di navigare tra le pagine di contenuto, dove ogni pagina è gestita dal proprio oggetto controller di visualizzazione" – shadowhorst

risposta

37

Quando si dispone di una vista bambini che hanno i propri controller di vista, si dovrebbe essere seguendo il modello di controllo contenitore personalizzato. Vedere Creating Custom Container View Controllers per ulteriori informazioni.

Supponendo che hai seguito il modello contenitore personalizzato, quando si desidera cambiare il controller della vista del bambino (e la sua vista associata) per la "vista dei contenuti", l'hai fatto a livello di codice con qualcosa di simile:

UIViewController *newController = ... // instantiate new controller however you want 
UIViewController *oldController = ... // grab the existing controller for the current "content view"; perhaps you maintain this in your own ivar; perhaps you just look this up in self.childViewControllers 

newController.view.frame = oldController.view.frame; 

[oldController willMoveToParentViewController:nil]; 
[self addChildViewController:newController];   // incidentally, this does the `willMoveToParentViewController` for the new controller for you 

[self transitionFromViewController:oldController 
        toViewController:newController 
          duration:0.5 
          options:UIViewAnimationOptionTransitionCrossDissolve 
         animations:^{ 
          // no further animations required 
         } 
         completion:^(BOOL finished) { 
          [oldController removeFromParentViewController]; // incidentally, this does the `didMoveToParentViewController` for the old controller for you 
          [newController didMoveToParentViewController:self]; 
         }]; 

Quando lo si fa in questo modo, non è necessaria alcuna interfaccia di protocollo delegato con il controller della vista del contenuto (diverso da quello che iOS fornisce già con i metodi Managing Child View Controllers in a Custom Container).


Tra l'altro, questo presuppone che il controllore bambino iniziale associato con quella vista il contenuto è stato aggiunto in questo modo:

UIViewController *childController = ... // instantiate the content view's controller any way you want 
[self addChildViewController:childController]; 
childController.view.frame = ... // set the frame any way you want 
[self.view addSubview:childController.view]; 
[childController didMoveToParentViewController:self]; 

Se si desidera un controller di bambino per dire al genitore di cambiare il controller associato alla visualizzazione del contenuto, è necessario:

  1. Definire un protocollo per questo:

    @protocol ContainerParent <NSObject> 
    
    - (void)changeContentTo:(UIViewController *)controller; 
    
    @end 
    
  2. Definire il controller principale conforme alla presente protocollo, ad esempio:

    #import <UIKit/UIKit.h> 
    #import "ContainerParent.h" 
    
    @interface ViewController : UIViewController <ContainerParent> 
    
    @end 
    
  3. Implementare il metodo changeContentTo nel controller principale (tanto come sopra):

    - (void)changeContentTo:(UIViewController *)controller 
    { 
        UIViewController *newController = controller; 
        UIViewController *oldController = ... // grab reference of current child from `self.childViewControllers or from some property where you stored it 
    
        newController.view.frame = oldController.view.frame; 
    
        [oldController willMoveToParentViewController:nil]; 
        [self addChildViewController:newController]; 
    
        [self transitionFromViewController:oldController 
             toViewController:newController 
               duration:1.0 
               options:UIViewAnimationOptionTransitionCrossDissolve 
              animations:^{ 
               // no further animations required 
              } 
              completion:^(BOOL finished) { 
               [oldController removeFromParentViewController]; 
               [newController didMoveToParentViewController:self]; 
              }]; 
    } 
    
  4. E i controllori figlio possono ora utilizzare questo protocollo in riferimento alla proprietà self.parentViewController fornita da iOS:

    - (IBAction)didTouchUpInsideButton:(id)sender 
    { 
        id <ContainerParent> parentViewController = (id)self.parentViewController; 
        NSAssert([parentViewController respondsToSelector:@selector(changeContentTo:)], @"Parent must conform to ContainerParent protocol"); 
    
        UIViewController *newChild = ... // instantiate the new child controller any way you want 
        [parentViewController changeContentTo:newChild]; 
    } 
    
+0

Questo è ciò che ho visto nella maggior parte delle implementazioni di visualizzazione contenitore su GitHub e ho dedotto questo dalla documentazione. C'è un modo per fare questo senza avere questo codice duplicato in ogni controller? – Alex

+1

@orbv Questo codice si trova solo nel controller principale, quindi non sono coinvolte duplicazioni. Forse non sto capendo la tua domanda. – Rob

+1

Xcode 5 ti consente solo di utilizzare una sequenza incorporata quando aggiungi una vista contenitore. Eviterei anche l'impostazione diretta dei frame se si utilizza il layout automatico. – Abizern

-2

Sembra che tu ti stia confondendo. Un contentView (supponendo UIView) non "contiene" un controller da scambiare. A UIViewController gestisce i suoi UIView. Mi sembra che tu abbia bisogno di una configurazione del controller di visualizzazione genitore-figlio.

Un controller di visualizzazione monoparentale, che gestirà i controller di visualizzazione figlio, ognuno dei quali è quindi possibile gestirli quando ciascuno viene visualizzato sullo schermo e regolare di conseguenza le visualizzazioni e i contenuti dell'utente. Si prega di consultare la documentazione di Apple qui sotto.

Container Programming - Apple Documentation

2

Per questo tipo di transizione è anche possibile utilizzare UIView.animateWith... animazioni.

Ad esempio, supponiamo che rootContainerView è contenitore e contentViewController controller attualmente attivo nel contenitore, quindi

func setContentViewController(contentViewController:UIViewController, animated:Bool = true) { 
    if animated == true { 
     addChildViewController(contentViewController) 
     contentViewController.view.alpha = 0 
     contentViewController.view.frame = rootContainerView.bounds 
     rootContainerView.addSubview(contentViewController.view) 
     self.contentViewController?.willMoveToParentViewController(nil) 

     UIView.animateWithDuration(0.3, animations: { 
      contentViewController.view.alpha = 1 
      }, completion: { (_) in 
       contentViewController.didMoveToParentViewController(self) 

       self.contentViewController?.view.removeFromSuperview() 
       self.contentViewController?.didMoveToParentViewController(nil) 
       self.contentViewController?.removeFromParentViewController() 
       self.contentViewController = contentViewController 
     }) 
    } else { 
     cleanUpChildControllerIfPossible() 

     contentViewController.view.frame = rootContainerView.bounds 
     addChildViewController(contentViewController) 
     rootContainerView.addSubview(contentViewController.view) 
     contentViewController.didMoveToParentViewController(self) 
     self.contentViewController = contentViewController 
    } 
} 

// MARK: - Private 

private func cleanUpChildControllerIfPossible() { 
    if let childController = contentViewController { 
     childController.willMoveToParentViewController(nil) 
     childController.view.removeFromSuperview() 
     childController.removeFromParentViewController() 
    } 
} 

questo fornirà u semplici animazioni dissolvenza, u può anche provare qualsiasi UIViewAnimationOptions, transizioni ecc

Problemi correlati