Introduzione
Nelle precedenti lezioni abbiamo mostrato come creare un sistema elementare di navigazione attraverso view multiple (UIView), pilotate da controllori differenti (UIViewController). Nella lezione di oggi, ci concentreremo su un altro interessante strumento utile per la navigazione di piu' viste: UITabBarController.
Vedremo come customizzare ognuna delle views che intervengono nel programma e come manipolare a nostro vantaggio la barra fornita da Apple: UITabBarController. Il risultato che otterremo e' illustrato in figura. Il codice sorgente puo' essere scaricato dal link in alto a destra.





AppDelegate ed analisi del problema
Dallo schema in alto, possiamo capire come andra' strutturata la nostra applicazione. Il controllore in basso (UITabBarController) gestira' per noi lo switch tra le varie views; avremo un controllore distinto per ognuna delle UIView. Adotteremo un metodo particolare di specializzazione della classe UIViewController, creando uno specializzatore a "runtime" attraverso un costrutto if..then..else, responsabile di gestire per noi le casistiche di inizializzazione diverse per ognuna delle opzioni possibili.
Gli oggetti controllori istanziati verranno salvati all'interno di un array (NSMutableArray), per poter essere referenziati successivamente e velocemente. La dichiarazione di interfaccia per il nostro AppDelegate sara' la seguente:




Nota come bisogna informare il compilatore del fatto che la nostra classe AppDelegate implementera' il protocollo UITabBarControllerDelegate. E' presente anche un metodo accessorio che ritorna un puntatore all'istanza dell'oggetto UITabBarController. Sarebbe stato possibile ottenere lo stesso risultato attraverso l'uso dei costrutti @property, @synthetize.

La parte implementativa del nostro appdelegate, inizializzera' 4 istanze diverse della stessa classe MyViewController. Ognuna di esse avra' un nome distintivo diverso, in maniera da poter discernere la sequenza di inizializzazione dell'oggetto piu' corretta. Il delegato dovra' preoccuparsi, inoltre, di conservare i puntatori di ognuno degli oggetti istanziati all'interno di una struttura adatta a questo scopo; useremo l'oggetto sopra dichiarato di tipo NSMutableArray, controllers.




L'oggetto UITabBarController
L'oggetto UITabBarController eredita direttamente da UIViewController. Questo significa che ci troviamo in presenza di un oggetto di tipo UIViewController piu' evoluto. In grado, quindi, di gestire l'evento a cui e' preposto. Esso e' composto da una View a schermo intero che contiene al suo interno una zona principale, in cui inseriremo le nostre subview (ed i relativi viewcontrollers) ed una zona di comando, contenente al suo interno un oggetto che eredita direttamente da UIResponder: UITabBar. Il grafico sotto illustra quanto esposto.




Per manipolare il suo contenuto agiamo attraverso l'uso di un messaggio proprio dell'oggetto UIViewController: setTabBarItem:(id). setTabBarItem prende come parametro un puntatore ad un oggetto UITabBar, opportunamente inizializzato attraverso il metodo di istanza:

- (id)initWithTitle:(NSString *)title image:(UIImage *)image tag:(NSInteger)tag

Il metodo sopra ci permette di specificare un titolo, un'immagine (automaticamente convertita in toni di grigio per soddisfare i requirements dettati dalla UIGL) ed un tag di identificazione. CocoaTouch mette a disposizione un massimo di 5 elementi per popolare la UITabBar. Superato questo numero, l'ultima view diventa un elenco (UITableView) delle restanti voci. Per il nostro esempio, utilizzeremo la versione base con un numero di 4 possibili scelte. Rimandiamo il lettore alle lezioni precedenti, riguardanti la gestione delle tabelle, per costruire una versione avanzata.




Facciamo un passo indietro e torniamo all'implementazione del delegato. Dopo aver inizializzato opportunamente l'oggetto UITabBarController:




Assegnamo come delegato la classe AppDelegate stessa e procediamo con l'inserimento di tutti gli oggetti UIViewControllers all'interno dell'oggetto NSMutableArray. Una volta completato questo task, ultimiamo l'inizializzazione del nostro UITabBarController.



Per completare l'inizializzazione, infatti, e' necessario assegnare alla property viewControllers l'oggetto NSMutableArray appena creato. Infine, selezioniamo la view di default da mostrare all'utente, attraverso la property selectedIndex.
All'interno della nostra window, opportunamente creata, inseriamo l'oggetto view del nostro UITabBarController. Sara' quest'ultimo a gestire la porzione di schermo disponibile per la visualizzazione delle ulteriori viste, secondo lo schema presentato sopra.



La classe multispecializzante
Ecco come si presentera' la dichiarazione di interfaccia per il nostro oggetto MyViewController:




La nostra classe eredita svariati "comportamenti", adottati attraverso l'uso dei protocolli: UIActionSheetDelegate, UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource. Il nostro oggetto dovrebbe, quindi, riuscire a rispondere correttamente ad ognuno dei metodi dichiarati come necessari all'interno dei protocolli di cui sopra. Dal momento che il nostro oggetto servira' per costruire istanze diverse - polimorfismo - con comportamento diverso, dovremo scrivere tutti i metodi necessari. L'unico metodo esposto e' quello di inizializzazione.



UITextField
La prima parte del costrutto if..then..else e' responsabile per l'inizializzazione di tutti i sotto-oggetti (concettualmente l'intero if, e' responsabile dell'inizializzazione dell'intera sottovista) al suo interno. Al suo interno trova posto un oggetto UITextField.




L'oggetto UITextField permette di gestire in maniera completa l'input/output. Esso offre svariate facilitazioni, tra cui l'impiego di una tastiera completa per la scrittura da parte dell'utente. Per poter trarre beneficio dalle funzionalita' offerte dall'oggetto, occorre adottare il protocollo UITextFieldDelegate come fatto in fase di dichiarazione.
La documentazione Apple, indica tutti i metodi del protocollo come opzionali. Questo significa che il nostro codice verra' compilato correttamente anche senza nessuno dei metodi indicati. Tuttavia, per poter trarre beneficio in maniera reale da quest'oggetto bisognera' scrivere del proprio codice all'interno di almeno un paio di metodi.




Nella figura sopra, sono indicati i due metodi implementati nel nostro codice d'esempio. In particolare, textFieldShouldReturn viene invocato per sapere se l'oggetto textfield gestira' la pressione del tasto RETURN sulla tastiera, apparsa preventivamente all'utente. Nel nostro caso, ritorneremo YES (bloccando la propagazione dell'evento), dopo aver riassegnato il focus dell'applicazione all'oggetto precedente. Perche' e' necessaria quest'istruzione?




La tastiera che viene presentata alla pressione del campo di testo e' un oggetto modale che cambia il focus della nostra applicazione. In altre parole, tutti gli oggetti sotto di essa, non risultano piu' attivi durante tutto il tempo in cui la tastiera e' presente a schermo. Alla sua chiusura (pressione del tasto DONE/Return), il metodo textFieldShouldReturn viene invocato per sapere come comportarsi. Il messaggio resignFirstResponder ristabilisce il risponditore corretto degli eventi, riassegnandoli alla nostra UIWindow.
Il secondo metodo viene invocato una volta conclusa la fase di digitazione (e dopo che il metodo textFieldShouldReturn e' stato invocato). textFieldDidEndEditing si occupa di effettuare tutte le operazioni necessarie dopo la fase di inserimento dell'input. L'aggiornamento della view, in funzione dei dati inseriti, ad esempio, dovrebbe esser effettuato in questa fase. Nel nostro caso ci occupiamo di aggiornare correttamente il valore dell'oggetto myLabel con il corrispondente valore della property text dell'oggetto UITextField.



UIPickerView
La seconda view, ci offre la possibilita' di interagire con un altro oggetto molto interessante: UIPickerView. UIPickerView si occupa di presentare all'utente il contenuto di una sorgente dati. Analogamente a quanto gia' visto per l'oggetto UITableView, sfrutteremo la struttura ad array (NSMutableArray) come sorgente dati.




Anche in questo caso e' necessario adottare un protocollo secondo quanto gia' visto nella fase di dichiarazione dell'interfaccia. Assegnando alla property delegate dell'oggetto UIPickerView appena instanziato, lo stesso oggetto UIViewController ( self ), indichiamo al compilatore che all'interno del nostro oggetto ( classe ) sono presenti tutti i metodi specificati dal protocollo UIPickerViewDelegate, necessari al corretto funzionamento.




In particolare, come per la gestione delle tabelle in UITableViewDelegate, e' necessario implementare almeno quattro metodi responsabili della presentazione a schermo del contenuto della sorgente dati (nel nostro caso NSMutableArray).
Il metodo numberOfComponentsInPickerView indica il numero di colonne di cui sara' costituito l'oggetto picker. Il numero di righe totali per ogni colonna e' dato dal metodo numberOfRowsInComponent:.
L'oggetto UIPickerView viene popolato con chiamate successive (una per ogni riga) al metodo titleForRow:(NSInteger)row forComponent:(NSInteger)component. Nel caso dell'esempio, bastera' fare corrispondere ad ogni riga del picker, una riga dell'array specificato come sorgente dati.
Il metodo didSelectRow:(NSInteger)row inComponent:(NSInteger)component, viene invocato ogni qualvolta si seleziona un elemento dell'oggetto picker. Il metodo viene invocato con il valore della riga corrispondente. Anche in questo caso, la riga ritornata dal metodo corrispondera' ad un elemento della sorgente dati NSMutableArray.



UIDatePicker
Una particolare specializzazione dell'oggetto Picker e' offerta dall'oggetto UIDatePicker. UIDatePicker si occupa di mostrare un particolare intervallo di date sotto forma di oggetto Picker. Non sara' necessario specificare una sorgente dati, in quanto l'insieme delle date disponibili nel range specificato viene gestito internamente dall'oggetto. Anche in questo caso, la nostra classe "super-specializzata" dovra' adottare un protocollo necessario al corretto funzionamento dell'oggetto UIDatePicker: UIDatePickerDelegate.




In fase di inizializzazione dell'oggetto specificheremo alcune properties, necessarie alla corretta visualizzazione dei dati. In particolare, l'intervallo di minuti per la scelta ( minuteInterval ), la data di partenza ( minDate ) e la data di fine ( maxDate ) del nostro intervallo. Infine, Attraverso l'uso del metodo addTarget: (anche UIDatePicker eredita da UIResponder) indichiamo il metodo da invocare alla selezione di un'opzione da parte dell'utente.






Riferimenti
- iPhone Dev Center: UITextField Class Reference
- iPhone Dev Center: UIPickerView Class Reference
- iPhone Dev Center: UIDatePicker Class Reference
- iPhone Dev Center: UITabBarController Class Reference
- iPhone Dev Center: UITabBar Class Reference
- Mac OS X Reference Library: Window and Views
- iPhone SDK Application Development - Capitolo 3



    lap1

downloads