In questo articolo tratteremo la classe UINavigationController tanto utile e cara a quasi tutti gli sviluppatori iPhone. La suddetta classe, per intenderci, è quella che consente di passare da una vista (UIViewController meglio) ad un’altra con la simpatica animazione dello scorrimento da destra a sinistra facendo apparire solitamente un tasto in alto a sinistra per tornare alla vista precedente. Ecco un esempio tratto dalla documentazione Apple:
Ma analizziamo ora in dettaglio come funziona questa classe.
UINavigationController non è altro che uno stack di UIViewController. Chi conosce un po’ di teoria del C capisce subito il suo funzionamento e può immaginare le sue possibili funzioni, ma per chi non lo sapesse ecco una breve spiegazione.
Immaginiamo lo stack come una pila di libri, ogni nuovo libro (in questo caso UIViewController) viene posto sopra a tutti gli atri e non è possibile rimuovere un qualsiasi altro libro, altrimenti la pila cadrebbe. L’unica soluzione è togliere un libro alla volta partendo dall’ultimo inserito, dal libro in cima.
Da questo ragionamento se ne deduce quindi la “filosofia” dello stack in generale:
“Il primo ad entrare è l’ultimo ad uscire“.
Di conseguenza si possono dedurre anche le azioni che potranno essere applicate allo stack:
- push (per aggiungere un elemento allo stack);
- pop (per togliere l’ultimo elemento inserito).
Il tutto sembra molto semplice, ed infatti lo è!
Portiamoci al caso specifico della classe trattata, dalla documentazione Apple si capisce subito la semplicità della classe e dei suoi metodi:
- – (id)initWithRootViewController:(UIViewController *)rootViewController per inizializzare l’oggetto con il primo elemento dello stack;
- – (void)pushViewController:(UIViewController *)viewController animated:(BOOL) animated per aggiungere un elemento allo stack;
- – (UIViewController *)popViewControllerAnimated:(BOOL)animated per togliere l’ultimo elemento inserito;
Lascio a voi analizzare gli altri metodi che sono delle estensioni dei due metodi principali e consentono principalmente di andare direttamente al primo elemento (eliminando sempre tutti gli atri elementi) o di andare ad un elemento predefinito o di ottenere un array con tutti gli elementi dello stack etc.
Piccoli dettagli per facilitarne l’uso
UINavigationController si utilizza con gli oggetti della classe UIViewController, ma come fare ad aggiungere questi ultimi al UINavigationController non avendo il riferimento (puntatore) a quest’ultimo oggetto?
Semplice:
ogni UIViewController ha una proprietà (navigationController) che è il puntatore al UINavigationController di cui esso fa parte. Mi spiego meglio con un esempio:
// inizializzo un UIViewController, sarà il primo dello stack
UIViewController *firstViewController = [[UIViewController alloc] init];
// inizializzo il mio UINavigationController con il primo elemento dello stack
UINavigationController *myNavigationController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[firstViewController release];
// rendo visibile la vista del myNavigationController
[window addSubview:myNavigationController.view];
[myNavigationController release];
Ora lo stack si presenta così
// firstViewController implementation
// ...
UIViewController *secondViewController = [[UIViewController alloc] init];
// aggiungo un altro elemento allo stack
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release];
Ora lo stack si presenta con un elemento in più:
Infine per tornare al UIViewController precedente basta fare:
// secondViewController implementation
// ...
[self.navigationController popViewControllerAnimated:YES];
19 Responses to “UINavigationController – Guida completa all’uso”
21 Marzo 2010
UINavigationController – Guida completa all’uso | Memegeek.it[…] – Guida completa all’uso Fonte: http://www.devapp.it/wordpress/uinavigationcontroller-guida-completa-all-uso.html In questo articolo tratteremo la classe UINavigationController tanto utile e cara a quasi […]
21 Marzo 2010
spiazziInteressante.
Ma per fare navigazione e mettere più form con un progetto view-based application?
22 Marzo 2010
paolinosiete veramente i migliori, pochi cavoli!!!
grazie!!
23 Marzo 2010
Francesco BurelliInserisci qui il tuo commento
Non ho ben capito cosa intendi per “form” comunque un progetto view-based è fatto principalmente per un’applicazione con una solo vista.
Ciò non preclude la possibilità di ampliarla, anche se sarebbe meglio iniziare con un progetto Window-based. Per adattare un progetto view-based basta inizializzare un oggetto della classe UINavigatorController con, come primo UIViewController quello che il progetto già ti dà, e rendere visibile la view del UINavigatorController.
27 Marzo 2010
AndreaSalve,
una semplice domanda per voi, ma molto complicata per me! Considerate che sono ignorante in materia. Se io volessi creare un applicazione per Iphone che abbia per intenderci esclusivamente un’icona nel menu e che cliccando sopra apra un sito web, già ottimizzato per iphone, è molto difficile da fare? C’è qualche guida o consiglio.
Grazie di cuore, ma navigo nel buio
27 Marzo 2010
Staff devAPPCiao Andrea, trovi tutte le risposte che cerchi nel nostro tutorial numero 8 inerente la creazione di un browser.. tu ovviamente semplificherai il tutto togliendo tutto quello che non ti occorre 😉
Eccoti il link per comodità:
http://www.devapp.it/wordpress/t008-creiamo-un-browser.html
Per il resto, ricorda che abbiamo un forum, chiedi li tutto quello di cui hai bisogno 😉
1 Novembre 2010
Silvio07Volevo sapere se all’interno di una vista di poteva mettere una NavigationController. Vi spiego meglio.
Ho una tapBar con 4 viste su file esterni, all’interno di queste viste è possibile mettere delle navigationController, quindi più viste? Eventualmente in che modo?
2 Novembre 2010
Francesco BurelliSi è possibile: la tabBar ha dei UIVIewController (non delle viste), tu puoi aggiungere quindi qualsiasi oggetto che sia una sottoclasse di UIViewController e UINavigationController lo è!
Quindi in sostanza quando usi il metodo “setViewControllers: animated:” per un UITabBarController aggiungi un array di UIVIewController che possono essere benissimo anche dei UINavigationController (essendo questo anche un UIVIewController).
2 Novembre 2010
Silvio07Non sono molto pratica ancora quindi non mi è chiaro. Praticamente io ho creato una finestra con una tapBar e ogni sezione punta a un file vista esterno. All’interno di uno di questo come la faccio funzionare la navigationController? Io per la prima vista della NavigationController avevo usato il metodo addSubview nel seguente modo:
[vista addSubview: navigationController.view] ma ovviamente non funziona :-(.
2 Novembre 2010
Francesco Burelliallora abbiamo due casi:
1 costruisci il UITabBarController via codice (scelta a mio parere migliore)
2 costruisci il UITabBarController con InterfaceBuilder
caso 1:
– costruisci il tuo UINavigationController come ti serve (chiamiamolo “navController”);
– costruisci gli altri UIViewController (“controller1”, “controller2”);
– costruisci il UITabBarController nel seguente modo:
UITabBarController *tabController = [[UITabBarController alloc] init];
NSArray *controllers = [NSArray arrayWithObjects:navController, controller1, controller2, nil];
[tabController setViewControllers:controllers animated:NO];
// rendere visibile il tabController, come? ad esempio:
[window addSubview:tabController.view];
######
considerazioni:
– a quanto ricordo la UITabBar non avrà i pulsanti, questi, infatti, vanno configurati in ogni viewController. esempio
UITabBarItem item = [[UITabBarItem alloc] init ……. etc ];
[controller1 setTabBatItem:item];
[item release];
– alla fine la tabBarController avrà 4 viste (in questo esempio) e queste viste saranno le viste di ogni UIViewController aggiunto. (ricordo ancora che un UINavigationController E’ un UIVIewController!!!)
caso 2:
– costruisci il tuo UINavigationController come ti serve (chiamiamolo “navController”);
– costruisci gli altri UIViewController (“controller1”, “controller2”);
– per settare le viste di ogni barButtonItem collega la voce “view” alla vista del corrispondente UIVIewController.
Il caso due non l’ho mai usato quindi non te ne assicuro il funzionamento, e comunque mi sarebbe più facile spiegarlo con uno screenshot che al momento non riesco a fare.
Il caso 1 sono sicuro al 99% che funzioni correttamente.
22 Gennaio 2011
Francesco De DonatisSalve,
premetto di essere alle prime armi e dunque perdonatemi sin da ora per eventuali castronerie. Vi chiedo aiuto per un applicazione che ho appena iniziato a sviluppare.
Ho la necessità di costruire due navigation controller, ognuno dei quali naturalmente contiene un insieme di view controller.
Ho definito nel nib file della MainWindow i due navigation controller e, in altri 5 nib files le view di cui, le prime tre le ho agganciate al primo navigation controller mentre le altre due al secondo.
Con l’istruzione
[window addSubview:navController.view];
specificata nell’application delegate in corripondenza dell’evento
didFinishLaunchingWithOptions,
ho fatto in modo di visualizzare il primo stack costituito da 3 view.
Se volessi creare un bottone che, dall’interno di una delle suddette view, mi facesse visualizzare il secondo navigation controller (navController2), come mi dovrei muovere?
Vi ringrazio anticipatamente.
Saluti
22 Gennaio 2011
Francesco BurelliCiao Francesco,
per iniziare un piccolo consiglio personale: non usare InterfaceBuilder, sembra tutto facile e funzionante, ma se non hai appreso ancora a fondo la mentalità della programmazione ad oggetti lascia perdere!
Un errore, per esempio, è mettere i due NavigationController nel MainWindow.nib, ora ti spiego: MainWindow.nib viene caricato appena parte l’app quindi all’avvio caricherà anche i due NavigationController! Ma a te non servono entrambi subito, giusto? Inizi con uno e poi quando servirà caricherai anche l’altro.
Le view che tu dici di aver “agganciato” ai NavigationController non so come tu le abbia “agganciate”, però per cominciare il NavigationController non prende UIView ma UIViewController e chissà che il tuo metodo di “aggancio” non le allochi già tutte e 3/5 non appena viene caricato il NavigationController… il che non è corretto. Lo stack è dinamico per qualcosa.
In generale se “sei in un navigationController” puoi accedere ad un altro facendo un “presentModalViewController..” dell’altro NavigationController.
Ascolta il mio consiglio: rifai tutto via codice, ti sarà tutto più chiaro, non usare IB.
8 Febbraio 2011
enricoCiao.
Ho un problemino con push e pop.
Ho due viste:
primaVista.xib e secondaVista.xib
Quando sono primaVista, alla pressione di un tasto faccio aprire (push) la secondaVista. Qui viene mostrata una tabella con delle opzioni. Al click su una di queste opzioni voglio che si torni a primaVista, e quindi utilizzo pop. E la cosa funziona bene. Solo che a questo punto la secondaVista mi viene come cancellata! Cioè se torno su secondaVista le opzioni che avevo settate sono scomparse. In qualche modo è come se quando uscissi (pop) dalla secondaVista questa venisse distrutta e venisse ricreata quando clicco sul tasto Opzioni della primaVista…
qualche tip in riguardo?
8 Febbraio 2011
Francesco BurelliE’ esattamente il comportamento che ci si deve aspettare, una volta che fai la pop il controller (che tu chiami vista) viene rimosso dallo stack e quindi rilasciato quindi “distrutto” perché si presuppone che non serva più. Ipotizza di avere N viste (controller), sei alla N-esima, fai N-1 pop è normale che vengano distrutti N-1 controller altrimenti sarebbe una cattiva gestione della memoria!
Nel tuo caso, per ottenere un effetto di persistenza devi configurare correttamente la seconda view di modo che quando viene caricata (loadView/viewDidLoad) o quando compare (viewWillAppare/viewDidAppare) setta i parametri giusti.
Per settare i parametri giusti posso immaginare una classe che memorizza le impostazioni e quando la secondaVista si carica legge i parametri da questa classe.
Non posso aiutarti di più perché non so bene tu cosa voglia fare, ma a grandi linee la teoria è questa.
21 Gennaio 2012
mauriziociao, ho letto vari tutorial e questo è uno dei più chiari.
volevo chiedervi: se parto da un progetto cocos2d e volessi aggiungere una finestra di settings con una UINavigationController, e sottofinestre, qual è il modo migliore per farlo?
ero partito creando delle finestre con l’interface builder, partendo con una finestra principale in cui ho aggiunto il NavigationController, evidentemente però lo avrò collegato male perchè non viene neanche visualizzato.
tutti i tutorial che ho visto modificano l’app delegate della mainWindow.xib, ma io ho creato una nuova finestra con IB e volevo utilizzare quella.
si potrebbe o esiste già un tutorial che parta da zero creando i delegate delle nuove finestre ecc..? grazie
23 Gennaio 2012
Francesco BurelliCiao,
no, non serve che tocchi l’app delegate o il file mainWindow.xib.
Non conosco il tamplate del progetto cocos2d ma cerco di aiutarti comunque.
Mettiamo caso che siamo nel metodo sollevato da un bottone (il bottone che aprirà la vista “settings”):
- (IBAction)showSettings:(id)sender {
// alloco e inizializzo il controller (Sottoclasse di UIVIewController) che contiene le settings
MySettingController *controller = [[MySettingController alloc] init o initWithNib...]; // se hai creato il controller con IB usa initWithNib... il controller creato con IB deve avere un suo file xib! Non deve esserci nel file mainWindow.xib!
// ora crei il UINavigationController
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:controller];
[controller release]; // il controller non ti serve più quindi lo rilasci
// ora devi far visualizzare il "nav" teoricamente qui siamo in un UIViewController credo (perché non so da dove attivi questo metodo) quindi basta fare
[self presentModalViewController:nav animated:YES];
[nav release];
}
Sono andato a memoria, magari qualche nome dei metodi è sbagliato, ma la logica è questa.
26 Gennaio 2012
mauriziograzie mi è stato di enorme aiuto, ora mi funziona
12 Settembre 2012
Gaetano CernigliaHo un problema, sto utilizzando Storyboard e come MainView un NavigationController. A parte il noto problema che la navigation bar viene visualizzata erroneamente a 44px di altezza anche se la view è landscape, va bene è un bug di IB e non ci possiamo fare niente.
Ma quando ruoto il dispositivo, sembra che il render della view venga effettuato senza tener conto della navigationBar e le mie view si spostano erroneamente verso l’alto, ho risolto riassegnando da codice la Y, ma è una cosa un po sporca visto che alla init devo settare la Y a 0 e alla rotation a navigationBar.height. Mi scuso se sono stato poco chiaro. Avete riscontrato questo problema? C’è un modo di evitarlo?
12 Settembre 2012
Francesco BurelliPersonalmente non uso IB, ma il “problema” lo conosco e si risolve semplicemente configurando correttamente la maschera di auto-resize. Via codice c’è il metodo setAutoresizingMask (devi settare la maschera con gli operatori or ( | )) oppure via IB c’è da qualche parte una figura che ti permette di configurare l’auto-size della vista.