2012-03-16 8 views
32

Configurazione: ho uno storyboard impostato, con due semplici controlli di visualizzazione A e B. C'è un pulsante in A, che passa a B con un passaggio modale. B è presentato con una transizione modale sopra A. Va bene.Come eliminare un modal che è stato presentato in un UIStoryboard con un passaggio modale?

Domanda: c'è un modo per far uscire B e tornare ad A con qualche semplice magia da storyboard?

Si noti che se questo era tutto in un controller di navigazione, e ho usato un push seguito, sarebbe implicitamente essere curato dal controller di navigazione. Ci sarebbe un pulsante "indietro". Non c'è nulla di paragonabile per le modali, ho bisogno di costruire l'interfaccia utente me stesso, ma mi chiedo se c'è una meccanica che posso usare per segnalare di tornare da B a A.

Ora il metodo oldskool per costruire tornando da B ad a sarebbe:

  • creare una proprietà delegato su B
  • insieme a essere delegato di B quando la segue di transizione modale riproduce (posso collegare in questo utilizzando prepareForSegue: mittente: in a di codice)
  • quando è il momento di respingere, B segnala al suo delegato
  • A implementa un metodo delegato che rifiuta B

Questo funziona, ma sembra troppo sovraccarico e sciocco.

C'è qualche meccanismo di UIStoryboard che mi è sfuggito, che fondamentalmente farebbe un "reverse modal segue"?

risposta

44

Non c'è alcuna magia di storyboard per chiudere un controller di visualizzazione modale senza scrivere almeno un po 'di codice.

Ma mentre è necessario implementare un codice proprio, non è necessario che si debbano affrontare così tanti problemi. È sufficiente avere un pulsante nel controller di visualizzazione B che chiama [self dismissViewControllerAnimated:YES completion:nil]. (I documenti dicono che il controller di presentazione che si presenta dovrebbe essere quello da licenziare, ma dicono anche che il messaggio verrà inoltrato al controller di visualizzazione che presenta se richiesto sul presente.) Se vuoi essere più esplicito a riguardo - e tu? In alcuni casi, come quando un presentatore modale viene presentato da un altro, è possibile fare riferimento esplicito al relatore con self.presentingViewController e chiamare il dismiss... da lì.)

Si vede il business delegato in alcune app perché è uno modo di notificare il controller di visualizzazione A su qualsiasi cosa l'utente abbia fatto mentre era nel controller di visualizzazione B ... ma non è l'unico modo. C'è KVO, notifiche o semplicemente chiamando i metodi di A dopo averlo fatto riferimento a self.presentingViewController (supponendo che B sappia che è sempre presentato da A). E se A non ha bisogno di sapere cosa è successo in B (diciamo, perché l'utente ha premuto un pulsante Annulla), non c'è bisogno di fare nulla di ciò - puoi semplicemente chiudere la modale e farla finita.


In iOS 6 e versioni successive, rilassarsi segues aggiungere un'altra opzione, che fornisce un po 'di "magia storyboard" per respingere i controller di vista modale (o in altro modo "marcia indietro" di una sequenza di segues). Ma questo approccio richiede ancora del codice: non è possibile impostarlo interamente nello storyboard. Tra l'altro, quel codice fornisce un percorso per ottenere informazioni dal controller di visualizzazione che viene rimosso (B) da quello che lo ha presentato (A).

Apple ha a tech note about unwind segues che li copre in dettaglio, ma ecco la versione corta:

  1. Definire un metodo IBAction sulla classe di visualizzazione del controller si desidera rilassarsi - - quella che presenta un modale guarda il controller, non il controller della modal view stessa (vedi il controller A nella tua domanda). A differenza dei normali metodi IBAction, questi dovrebbero prendere un parametro di tipo UIStoryboardSegue *; per esempio.

    - (IBAction)unwindToMainMenu:(UIStoryboardSegue*)sender 
    
  2. Nel controller della vista presentato (B in questione), filo di un controllo per l'icona Esci verde, e scegliere il metodo definito.

  3. Nell'implementazione del metodo di svolgimento, è possibile fare riferimento allo sourceViewController del seguito per recuperare le informazioni dal controller di visualizzazione che viene rimosso. Non è necessario chiamare lo dismissViewControllerAnimated:completion: perché la procedura di gestione dei passaggi ignora il controller della vista che sta andando via.

+0

Cool, non sapeva del PresentationViewController (apparentemente un nuovo iOS 5 cosa), che aiuta. – Jaanus

+2

Sì, se vuoi farlo in un seguito personalizzato per un facile riutilizzo puoi fare qualcosa come - (void) eseguire { UIViewController * src = (UIViewController *) self.sourceViewController; [src.presentingViewController dismissModalViewControllerAnimated: YES]; } – AppHandwerker

+0

@SimonH Il miglior consiglio per i segues! –

30

Ci è magia storyboard per raggiungere questo obiettivo. È conosciuto come un seguito di svolgimento. Nel file .h di A si implementa qualsiasi metodo di stile di "azione mirata" di cui si ha bisogno per molti segui di svolgimento necessari. Per un modale, di solito è due (cancella e salva). Così nel mio file Ah io aggiungerei:

// A.h file 
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue; 
- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue; 

Ora, nel vostro storyboard, se si dispone di un segue da A a B. È ora possibile fare un ' "azione target" di trascinamento di controllo stile dai vostri pulsanti Annulla/salvataggio in B all'icona verde "Esci" nella parte inferiore del controller B nello storyboard. Quando lo fai, Xcode raccoglierà i due metodi che abbiamo creato (poiché sono nel file di intestazione di A e hanno la firma corretta (es. IBAction e UIStoryboardSegue *.) E B è la destinazione di un seguito da A) Quindi, Ecco qua. Hai la magia dello storyboard che stavi cercando!

Per l'attuazione dei due callback, si sarebbe qualcosa come:

// A.m file 
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue { 
    UIViewController *modalGoingAway = segue.sourceViewController; 
    // Do something (like get data) from modalGoingAway if you need to... 
} 

- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue { 
    UIViewController *modalGoingAway = segue.sourceViewController; 
    // Do something (like get data) from modalGoingAway if you need to... 
} 

Infine, se questo approccio soddisfa le vostre esigenze, grande. Hai finito. Tuttavia, continuo a collegare l'intero modello di design delegato/dataSource del protocollo se "on cancel" o "on save" Voglio eseguire alcune operazioni sulle proprietà private di B prima di passare il controllo ad A per rimuovere B dalla gerarchia della vista.

+1

si prega di notare 2 cose: 1) in callback non è necessario chiudere il modal perché verrà automaticamente eliminato da unwind segue (e causerà un errore se si tenta) 2) Svolgere azioni di follow (pulsante di uscita verde) funziona con iOS6 bersaglio. è un po 'confuso perché con un target più vecchio vedrai il pulsante di uscita verde che non ha significato) –

+1

Non è proprio l'intera "storyboard magic" perché devi ancora aggiungere codice al tuo controller di visualizzazione A. Ma nel mio caso, B è solo contenuto statico, quindi questo batte dover creare una sottoclasse di controller B view solo per eliminarla. – jab

Problemi correlati