Nella guida di oggi approfondiremo un componente molto utilizzato all’interno delle applicazioni per iphone, stiamo parlando di UIPickerView (e UIDatePicker).
Lo studio di questi due oggetti ci permetterà di chiarire il concetto di delegate e di vedere all’opera il paradigma mvc (model-view-controller)
Diamo un’occhiata alla gerarchia delle classi per capire di cosa ci occupiamo oggi:
Come nostra consuetudine i nomi bordati in verde si riferiscono a classi già trattate su questo stesso sito [qui], mentre quelli bordati in rosso sono quelle che analizzeremo in questo articolo.
Concorderete con me che non c’è sistema migliore per studiare una classe se non quella di scaricare la class reference dal sito della apple, (ok, ok, a parte leggere il sorgente 🙂 ) ecco quindi due link per un facile download:
UIPickerView Class Reference
UIDatePicker Class Reference
Iniziamo analizzando il più semplice tra i due, l’ UIDatePicker (che non necessita di delegate) trasciniamone uno su una view oppure inserendo questo codice per generarlo a runtime:
UIDatePicker *datePicker;
datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 150, 0, 0)];
[self.view addSubview:datePicker];
da notare che non importano le dimensioni del frame, il picker ha dimensione fissa.
Vediamo quali sono le più comuni proprietà e metodi che questo oggetto ci mette a disposizione:
maximumDate & minimumDate:
@property(nonatomic, retain) NSDate *maximumDate
@property(nonatomic, retain) NSDate *minimumDate
permettono di limitare il range di variabilità della data impostando la data massima e la data minima selezionabile. Di default vengono impostate entrambe a nil quindi l’utente può selezionare una data arbitrariamente passata o futura.
esempio: (questo esempio è complicato dall’utilizzo della classe nsdate che vedremo un’altra volta.)
NSString *min = @"20042010";
NSString *max = @"22042010";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"ddMMyyyy"];
NSDate *datemin = [dateFormat dateFromString:min];
NSDate *datemax = [dateFormat dateFromString:max];
[self.view addSubview:datePicker];
datePicker.maximumDate = datemax;
datePicker.minimumDate = datemin;
minuteInterval:
@property(nonatomic) NSInteger minuteInterval
Indica l’intervallo di selezione dei minuti, di default viene posto a 1 ma possiamo modificarlo, purché ci limitiamo ad inserire divisori di 60 (per esempio 2, 5, 30 ma non 23 oppure 45)
datePicker.minuteInterval = 30;
setDate:animated:
questo metodo permette di impostare una data nell’ UIDatePicker a runtime, se animated è impostato a YES verrà visualizzata l’animazione delle rotelle che girano.
datePickerMode:
@property(nonatomic) UIDatePickerMode datePickerMode
Questa proprietà determina l’aspetto delll’UIDatePicker, se permette la selezione di una data, di un orario, di entrambi o un conto alla rovescia. Il valore di default è UIDatePickerModeDateAndTime.
Gli altri possibili valori sono:
UIDatePickerModeTime
UIDatePickerModeDate
UIDatePickerModeDateAndTime
UIDatePickerModeCountDownTimer
Veniamo ora al secondo argomento di questa guida, parliamo di UIPickerView.
Proviamo come poc’anzi a creare un pickerview e visualizzarlo nella nostra applicazione:
UIPickerView *Picker;
Picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 150, 0, 0)];
[self.view addSubview:Picker];
Purtroppo il codice sembra non funzionare, il picker non si vede ed al suo posto otteniamo soltato un rettangolo nero, come mai? Ci viene in aiuto la class reference che dice:
“A UIPickerView object requires the cooperation of a delegate for constructing its components and a data source for providing the numbers of components and rows.”
Che per chi non mastica l’inglese vuol dire:
“Un oggetto UIPickerView richiede la cooperazione di un degate per costruire i suoi componenti e di un data source che proveda a fornire il numero dei componenti e delle righe.”
Quindi poichè al nostro pickerview non abbiamo specificato nè delegate nè datasource, non è in grado di visualizzare nulla, ecco quindi spiegato il rettangolo nero.
Concettualmente delegate e dataprovider potrebbero essere due classi separate e create appositamente per tale scopo, ma spesso viene dato il compito di assolvere a questi ruoli allo stesso File’s Owner dell’uipickerview. Per fare questo quindi scriviamo:
[Picker setDelegate:self];
[Picker setDataSource:self];
Se provassimo adesso ad eseguire il codice vedremmo crashare inesorabilmente la nostra applicazione, ma anche a questo c’è una spiegazione… abbiamo detto al pickerview di interpellare il suo File’s Owner (self) per ricevere tutte le informazioni necessarie per la sua visualizzazione, ma non abbiamo detto al File’s Owner cosa rispondere, quindi in questo empasse l’applicazione va in crash.
Diamo quindi un’occhiata alla reference apple per UIPickerViewDelegate (qui)
scopriamo che la classe che vuol fare da delegare ad un uipickerview deve implementare almeno uno tra questi due metodi:
– pickerView:titleForRow:forComponent:
– pickerView:viewForRow:forComponent:reusingView:
Il secondo è meno utilizzato perché si usa per visualizzare immagini all’interno del picker piuttosto che una descrizione testuale;
Aggiungiamo quindi alla nostra classe questo metodo:
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
return [NSString stringWithFormat:@"VALORE NUM:%d",row];
}
non abbiamo ancora terminato, abbiamo implementato il delegate, resta da implementare il datasource.
Leggiamo quindi sempre dalla reference apple (qui) che i metodi da implementare sono tutti e due, e sono:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
Il primo specifica quante “rotelle” devono essere disegnate nel picker, mentre il secondo specifica, per ogni “rotella” quanti devono essere i valori presenti. Nel nostro caso possiamo quindi aggiungere:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return 20;
}
eseguiamo quindi il nostro codice e godiamoci finalmente il nostro UIpickerView!
La trattazione di questi oggetti è stata particolarmente lunga e non è affatto esaustiva, invito per tanto tutti a leggere le reference apple per riuscire a sfruttare al massimo questi oggetti.
Un ultimo consiglio per gli amanti di interface builder, potete trascinare i picker come trascinereste qualsiasi altro oggetto, ricordatevi però di impostare nella finestra “connection” il corretto delegate e datasource (ctrl e trascina)
15 Responses to “UIPickerView e UIDatePicker – Guida all’uso”
23 Aprile 2010
andreagrandissimo tutoria..:) non so come farei senza di voi….:) una cosa, sulle reference non mi sembra di aver trovato niente riguardo la personalizzazione della grafica. es: io avrei bisogno di rendere lo sfondo(quello grigio) trasparente ma non ci son ancora riuscito…
23 Aprile 2010
Ignaziocin effetti non sembra che apple fornisca property per modificare lo sfondo, probabilmente dovresti costruire una sottoclasse ed eseguire l’override di quello che preferisci.
considera però che è sconsigliato modificare radicalmente la grafica dei controlli, se la apple li ha fatti in un modo c’è un motivo..studi dietro..
23 Aprile 2010
andreasi lo so…. solo che far vedere quello sfondo grigio puo risultare brutto a volte..:) cmq grazie!!
24 Aprile 2010
Mokka77Ma ragazzi.. Queste guide sono FANTASTICHE!! Bravi!!!!!!
A proposito, non sono espertissimo, potresti farmi un esempio per inserire le immagini dentro? Grazie!!
24 Aprile 2010
LuigiCiao Ignazio complimenti.
Ti sottopongo una domanda per un app in cui sto usando il Picker.
Supponiamo che tu abbia una tableView ed a seconda della cella selezionata devi caricarti un picker ( e fin qui nessun problema )
Supponiamo però che nella classe iniziale tu abbia un dictionary nel quale i “chiave – valore” vengono influenzati dalla scelta del picker.
Mi spiego:
Entro nella classe 1, seleziono la cella, vado nel picker e scelgo. Quello che ho scelto devo metterlo in un dizionario della classe 1.
Sto trovando difficoltà perchè ovviamente gli oggetti delle classi non puo accederci ( a meno che non fai una nuova istanza ma in quel caso avresti tutti i valori di nuovo a zero ).
Tu cosa consiglieresti?
Su internet ho trovato qualcosina ma prima di addentrarmi vorrei un tuo consiglio
Grazie
24 Aprile 2010
Ignazioc@mokka77
se leggi bene il metodo, vedi che devi restituire una uiview quindi pui fare così:
[code]
UIImage *logo = [UIImage imageNamed:@”logo.png”];
UIImageView *logoView = [[UIImageView alloc] initWithImage:logo];
return logoView;
[/code]
@luigi
difficile darti una risposta senza vedere in dettaglio qual’è il problema.
sembra che il tuo picker faccia parte di un’altra classe, questo è necessario? non potresti inserirlo nella tua classe principale?
se invece devono stare su due classi separate chi ha detto che non ci puoi accedere? devi utilizzare i metodi set e get oppure più semplicemente imposti il tuo picker come @property.
per qualsiasi necessità contattami pure.
24 Aprile 2010
LuigiSi purtroppo la situazione è per forza quella che ti ho esposto.
secondo te la soluzione migliore “stilisticamente” non sarebbe quella di creare un’istanza condivisa?
Guarda qui ( http://www.drobnik.com/touch/2009/05/the-death-of-global-variables/#more-878 ) al paragrafo Shared Instance in basso
2 Giugno 2010
Accedere a Flickr dalle nostre applicazioni iPhone e iPad | devAPP[…] della programmazione per iphone. Abbiamo già parlato di delegate nell’articolo relativo all’UIPickerView, e anche se parliamo di oggetti diversi la logica che ci sta dietro è identica. In particolare […]
26 Agosto 2010
JasonCome sempre COMPLIMENTI!! sto provando ad utilizzare UIDatePicker in un’applicazione e non riesco a capire come prelevare la data visualizzata dal picker ed inserirla in una label… qualche suggerimento? grazie!!
30 Settembre 2011
antonioRagazzi questa guida è fatta malissima!
poco intuitiva!!
30 Settembre 2011
IgnaziocSono l’autore dell’articolo se c’è qualcosa che non è chiaro chiedi pure sul forum, vedremo di essere più chiari.
ciao.
17 Novembre 2011
giovanniesiste la possibilità di usare un uidatepicker solo con mese e anno senza giorni?
22 Maggio 2012
fabioma non è possibile customizzare il numero di righe per ogni component???
20 Agosto 2012
SilviaSalve, ho un problema il picker mi appare , il sistema nn va in crash, ma non mi appare all interno del picker i dati da me passati nel didload perche?
18 Novembre 2012
AngeloCiao, è possibile cambiare il testo dell’array tramite, per esempio, delle textView?