2011-11-20 10 views
55

È possibile associare controller di visualizzazione figlio a un controller di visualizzazione contenitore personalizzato in Storyboard?Collegamento di controller di visualizzazione figlio a un controller di visualizzazione padre nello storyboard

Posso collegare i controller di visualizzazione figlio a un controller di visualizzazione a schede e posso collegare un controller di visualizzazione a un controller di navigazione.

Cosa devo fare al contenitore VC per accettare VC figlio?

risposta

75

come una sorta di combo di Caleb e risposte di Matt, ho fatto:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 
    if ([segue.identifier isEqualToString:@"cpdc_check_embed"]) { 
     self.checkVC = segue.destinationViewController; 
    } 
} 

...dove checkVC è una struttura sul controller del contenitore:

@property (weak,nonatomic) PXPCheckViewController * checkVC; 

Non vi resta che impostare il embed di Storyboard ID per quello che vuoi segue (in questo caso, cpdc_check_embed):

check embed screen in Xcode

... e quindi controllare l'identificatore in -prepareForSegue:sender:.

non

Ancora una presa di corrente, ma più pulito di quello di Matt (IMHO) e più specifico di Caleb, ed è ancora un bel aspetto storyboard:

enter image description here

+1

Stai utilizzando una procedura di incorporamento, che è una funzionalità di iOS 6. La mia domanda risale a novembre 2011. :-p –

+0

Sì. Ho appena realizzato che sto lasciando il gatto fuori dalla borsa un po '. Ho cercato di installare sul telefono 5.1.1 di un cliente; niente da fare. –

+1

Ora che iOS 6 è stato rilasciato, questa è la risposta corretta. – awolf

7

È possibile associare i controller di visualizzazione figlio a un contenitore personalizzato con il controller in Storyboard?

Penso che quello che stai chiedendo qui è come collegare un controller di visualizzazione in una scena a una presa di un controller di vista in una scena diversa. Non credo sia possibile, forse perché i macchinari dello storyboard potrebbero non avere tutte le scene di uno storyboard caricate nello stesso momento.

Probabilmente lo stai chiedendo perché vuoi passare alcune informazioni da un controller di visualizzazione a un altro mentre passi da una scena all'altra. Il modo per farlo quando si lavora con gli storyboard è di ignorare lo -prepareForSegue:sender: in uno o entrambi i controller di vista interessati dal seguito. L'oggetto UIStoryboardSegue fornito nel parametro segue ha proprietà sourceViewController e destinationViewController e anche una proprietà identifier. È possibile utilizzare queste proprietà per identificare i passaggi che stanno per trasferire i dati tra i controller della vista.

blog di Ray Wenderlich ha un bel tutorial in due parti sull'utilizzo di storyboard che possono aiutare:

  • Part 1 copre la creazione di un progetto di storyboard, aggiungendo scene, e la creazione di segues.

  • Part 2 si occupa dell'utilizzo dei segui per la transizione tra le scene, incluso il metodo prepareForSeque menzionato sopra.

IOS 5 consente a più controller di vista di essere attivi nella stessa scena (anche se occorre ancora in carica), per cui un singolo scena storyboard può avere più controllori. È possibile utilizzare le prese per connettere tra loro questi controllori e configurare tali connessioni nello stesso modo in cui si è fatto in IB: trascinare il controllo da un controller a un altro nella stessa scena. La solita lista di prese si aprirà per permetterti di scegliere quale presa collegare.

+1

No, intendo utilizzare due controller di vista contemporaneamente. Un controller della vista _container_ che contiene se stesso più controller _child_ view. Qualcosa come il controller della vista divisa, che contiene un controller della vista principale e un controller della vista dettagliata, ma i figli del controller della vista divisa (il VC principale). –

+3

In tal caso, trascinare un oggetto NSO dalla libreria nel dock per la scena in cui si desidera contenere il controller di visualizzazione figlio. Imposta il tipo dell'oggetto sulla classe del controller di visualizzazione. Dopodiché puoi controllare e trascinare per creare connessioni da o verso altri oggetti, inclusi altri controller di vista nella scena. Ciò che non è possibile fare, come spiegato sopra, è di creare connessioni tra oggetti (controllori della vista o altro) in scene diverse. – Caleb

+0

Quindi, a differenza dei controller di visualizzazione contenitore di Apple, tutti i controller di visualizzazione (figlio e genitori) devono essere all'interno della stessa scena se voglio visualizzarli contemporaneamente. Bene, fa il lavoro e questo è tutto ciò che volevo. Grazie! –

5

La chiave per l'utilizzo di più controller in una scena (quello che ritengo sia dopo) utilizza l'Oggetto misterioso dall'elenco Oggetti in IB per rappresentare l'altro controller di visualizzazione e collegarne le uscite.

Questa risposta How to create custom view controller container using storyboard in iOS 5 dovrebbe aiutare a sperare. La risposta fornisce anche un'app di esempio di lavoro che è molto utile.

15

Lo storyboard gestisce molto bene i controller di visualizzazione contenitore incorporati, visualizzando i segui ai controller di visualizzazione figlio/radice in modo che le relazioni vengano visualizzate in modo chiaro. È anche interessante il modo in cui i controller di visualizzazione di bambini e genitori sono separati in scene diverse.

Se si vuole ottenere questo effetto nel proprio progetto, allora c'è un trucco che non è perfetto ma molto semplice.Nel mio esempio, supponiamo di avere un controller di visualizzazione contenitore che si comporta come un controller di barra di tabulazione con solo due schede, 'sinistra' e 'destra'. Voglio che una scena rappresenti il ​​controller della vista genitore e due scene separate rappresentano sia il controller di visualizzazione figlio "di sinistra" sia il controller di visualizzazione figlio "giusto".

Anche se è impossibile, sarebbe bello se potessi creare IBOutlet s dal controller della vista contenitore per i suoi figli in diverse scene, e poi quando il mio controller della vista contenitore viene visualizzata impostare le relazioni padre/figlio in base alle le regole descritte lo UIViewController documentation. Se avessimo riferimenti ai nostri controllori di vista figlio 'sinistra' e 'destra', allora potremmo impostare le relazioni senza problemi.

La soluzione standard a questo problema riferimento è quello di creare i riferimenti ai controller di vista bambino trascinando in Object punti vendita in scena la vista del controllore contenitore, e specificando il loro tipo di classe come istanze delle classi controller della vista del bambino.

Al fine di tenere i bambini separati in scene diverse come i contenitori integrati Apple, tuttavia, useremo un trucco diverso. In primo luogo, supponiamo di avere le seguenti proprietà dichiarate nella nostra classe contenitore, ContainerViewController:

@property (nonatomic, strong, readwrite) UIViewController *leftViewController; 
@property (nonatomic, strong, readwrite) UIViewController *rightViewController; 

Nel nostro storyboard, selezionare la scena che rappresenta il controller 'left' vista. Nell'ispettore attributi, impostare la proprietà identifier del controller di visualizzazione su "cvc_leftViewController" ("cvc_" si riferisce a , ma in realtà l'identificatore può essere qualsiasi cosa si desideri). Fai lo stesso per la scena del controller della vista giusta, impostando il suo identificatore su "cvc_rightViewController".

Ora inserire il seguente codice nel 'viewDidLoad metodo s:

if (self.storyboard) { 
    _leftViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_leftViewController"]; 
    _rightViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_rightViewController"]; 
} 

Quando ContainerViewController viene caricato dallo storyboard, andrà afferrare il 'ContainerViewController' e '' vista controllori destra e sinistra dalle loro rispettive scene e impostare i riferimenti a loro tramite le sue proprietà. Ora che hai il controllo delle istanze del controller della visualizzazione figlio, puoi impostare le relazioni genitore/figlio come preferisci. Per sapere come farlo correttamente, fare riferimento allo UIViewController documentation.

Questo trucco non è perfetto e presenta molti avvertimenti, ma se si sta attenti, è possibile farlo funzionare correttamente per il progetto.

Edit: Anche se questo è completamente inutile e non significa nulla, se davvero veramente vogliono avere i collegamenti di visualizzazione dello storyboard dal contenitore al vostro bambino view controller proprio come Apple integrato in contenitori, basta usare la mia il metodo sopra descritto e quindi impostato passa direttamente dalla scena contenitore alle scene figlio e semplicemente non esegue mai quelle seguite. Ora tutto funzionerà correttamente e sarà anche bello.

+1

+1 Sembra una buona tecnica e hai ragione che imita il modo in cui i controller della vista contenitore di Apple funzionano negli storyboard. Lo svantaggio principale rispetto alla creazione dei controller di visualizzazione figlio nella stessa scena del contenitore è che non è possibile creare connessioni tra le scene. Quindi, se vuoi impostare il delegato di un controller figlio sul controller genitore, devi farlo in codice - non puoi semplicemente trascinare una connessione. – Caleb

+1

Vero. Inoltre, ho sempre un po 'nervoso basare le connessioni su stringhe di identificazione piuttosto che sulla sensazione di stabilità che viene fornito con le prese. – Matt

+0

Cool hack! Lo userò nelle mie app iOS 5 esistenti come adesso. Il mio progetto sarà molto più semplice. Apple ha risolto il mio problema per iOS 6 (con le viste del contenitore del controller di visualizzazione direttamente in Storyboard/IB), ma è per le nuove app o quando decido di abbandonare iOS 5 in 2-3 anni per le app esistenti. –

4

Il problema con @ di Ben (altrimenti ragionevole) la risposta è che funziona solo a un livello di annidamento. Oltre a ciò, è necessario che ogni VC successivo sia personalizzato per salvare il controller della visualizzazione nesting in prepareForSegue.

Per risolvere questo problema, ho dedicato troppo tempo all'esplorazione di un indice basato su NSObject che è possibile aggiungere allo Storyboard, associare a una scena e registrare quindi il VC principale in un indice globale, in base al tipo e al ripristinoId . Funziona/può funzionare, ma alla fine è troppo impegnativo, e richiede ancora il processo in due fasi di visualmente vincolante e di ricerca a livello di codice.

Per me, la soluzione più semplice e più generale è di scendere pigramente la gerarchia vista del regolatore

Nel mio semplice progetto di test, ho aggiunto le seguenti righe viewDidLoad:

self.left.data = [ 
     "Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.", 
     "De carne lumbering animata corpora quaeritis." ] 

in cui è definito left come:

lazy var left:CollectionViewController = { [unowned self] in 
    return self.childViewControllerWithId("Left") as! CollectionViewController }() 

e childViewControllerWithId è definito come:

extension UIViewController { 
    func childViewControllerWithId(rid:String) -> UIViewController? { 

     // check immediate child controllers 
     for vc in self.childViewControllers as! [UIViewController] { 
      if vc.restorationIdentifier == rid { return vc } 
     } 

     // check nested controllers 
     for vc in self.childViewControllers as! [UIViewController] { 
      if let vc = vc.childViewControllerWithId(rid) { 
       return vc 
      } 
     } 

     assert(false, "check your assumptions") 
     return nil 
    } 
} 

Si noti che è possibile eseguire altre varianti find in base al tipo, se necessario. Si noti inoltre che quanto sopra richiede la definizione dell'ID di ripristino nel file Storyboard. Se non hai ripetuto istanze dello stesso controller di visualizzazione, l'utilizzo del tipo sarebbe più semplice.

E per stabilire cosa si spera sia ovvio, non è necessario implementare prepareForSegue, né è necessario utilizzare il caricamento lazy, è sufficiente chiamare find(...).

Problemi correlati