Rieccoci con un breve tutorial! Oggi vogliamo rispondere ad una domanda che ci è stata fatta diverse volte sul nostro forum: “Come riuscire ad implementare nella nostra applicazione iPhone una subView personalizzata simile a questa mostrata in figura qui a lato?”
Come spesso accade, non c’è un solo modo per realizzare una view simile per aspetto e funzionalità a quella in foto, ciascun programmatore è libero di esprimersi come meglio crede e, a meno di profondi errori, non c’è un metodo giusto ed uno sbagliato.
Io personalmente amo generalizzare e mi piace scrivere codice, magari più prolisso, ma che può essere riutilizzato in altri contesti. Questo tutorial segue proprio la mia filosofia. Alla fine infatti ci ritroveremo con due file .h e .m che possono essere copiati ed usati in un nuovo progetto senza modificare una riga di codice.
A dire il vero questo codice non è “completamente” generalizzato, in quanto gli slider eseguono una funzione predefinita, in pratica possiamo riutilizzare sì questa classe, ma solo per modificare un colore, mentre se avessi generalizzato anche la funzione associata avremmo potuto utilizzarla davvero per qualsiasi cosa. (Magari potremo vederlo in un prossimo tutorial)
Creiamo un nuovo progetto
Iniziamo quindi con il creare un nuovo progetto, per seguire questo tutorial può andare bene anche un template di tipo “view based application”. Creato il nostro progetto aggiungiamo una nuova classe cliccando sul menù file -> new file e scegliendo l’icona di “objective-c Class”. Selezioniamo “UIview” dalla casella “Subclass of” e clicchiamo su next. Inseriamo un nome significativo e clicciamo su “finish”. Io in un volo di fantasia l’ho chiamata “editView”.
Questa che abbiamo creato è quindi una nuova classe che eredita dalla classe UIView. Se avete già letto qualcosa su OOP vi sarà già chiaro che il grosso del lavoro è già stato fatto, tutti i metodi e le proprietà utilizzabili su un’oggetto di tipo UIView sono già automaticamente utilizzabili anche sulla nostra classe, non ci resta che personalizzarli.
Importiamo e dichiariamo gli elementi necessari
Visualizziamo il file editView.h che abbiamo creato ed aggiungiamo in testa, la direttiva
#import
Quartz è un framework che ci permette di disegnare sullo schermo oggetti che non sono facilmente rappresentabili con UIKit, come per esempio la nostra view dagli angoli arrotondati.
Purtoppo la sola direttiva non è sufficiente a far si che il framework venga importato, bisogna aggiungerelo al progetto cliccando con il tasto destro (non ditemi che il mac non ha il tasto destro, please!) sulla cartella “frameworks” e selezioniamo “add -> existing framework” e aggiungiamo quindi “QuartzCore”

Aggiungiamo quindi le proprietà che servono alla nostra view, io ho aggiunto queste:
@interface editView : UIView {
UISlider *redSlider;
UISlider *greenSlider;
UISlider *blueSlider;
UILabel *red_text;
UILabel *green_text;
UILabel *blue_text;
UIView *target;
}
@property (nonatomic, retain) UIView *target;
@property (nonatomic, retain) UISlider *redSlider;
@property (nonatomic, retain) UISlider *greenSlider;
@property (nonatomic, retain) UISlider *blueSlider;
Gli slider serviranno per modificare il colore della view specificata, mentre le label mostreranno il valore dello slider.
E la view “target” cos’è? Spero si capisca leggendo il codice, perché non è facile spiegarlo a parole 🙂 in breve la view “target” fa da segnaposto (come i parametri formali delle funzioni) e viene correttamente valorizzata od ogni utilizzo della view.
Passiamo all’implementazione
Nel file editView.m troviamo alcuni metodi già scritti per noi, Xcode li ha aggiunti per semplificarci la vita.
Cerchiamo e modificichiamo quindi il metodo:
- (id)initWithFrame:(CGRect)frame
per far si che venga generata la view per come la desieriamo.
Ho deciso di non attribuire una dimensione fissa alla view, questo complica le cose ma ci tornerà utile se vogliamo utilizzarla in un altro progetto in cui lo spazio a disposizione è diverso. Ho limitato però la dimensione ad almeno 200px x 200px e l’ho fatto con un metodo un pò strano, utilizzando questo codice:
- (id)initWithFrame:(CGRect)frame {
assert(frame.size.width >= 200);
assert(frame.size.height >= 200);
[...]
Ovviamente l’ho fatto a solo scopo didattico, perché la funzione assert genera una eccezione sel il suo parametro è false, quindi se viene dichiarata una view con un lato minore di 200 pixel il programma va in crash e si chiude. La funzione quindi risulta utile solo in fase di debug, perchè nell’applicazione finale dovrà essere sostituita con una reale gestione dell’errore.
Il codice prosegue con:
if ((self = [super initWithFrame:frame])) {
Invochiamo il metodo initiWithFrame della superclasse e ci assicuriamo che non restituisca null.
self.layer.cornerRadius = kDefaultCornerRadius;
self.backgroundColor = kDefaultRectColor;
self.alpha = kDefaultAlphaValue;
[self.layer setBorderColor:[[UIColor whiteColor] CGColor]];
[self.layer setBorderWidth: 2.0];
Qui stiamo creando la view vera e propria, utilizzando dei metodi forniti da Quartz. I valori utilizzati come parametro sono stati definiti in testa al file tramite il costrutto #define.
#define kDefaultRectColor [UIColor blackColor]
#define kDefaultCornerRadius 20.0
#define kDefaultAlphaValue .8
A questo punto bisogna iniziare a creare la view via codice, ma non possiamo utilizzare riferimenti statici per gli slider, perchè abbiamo detto che la dimensione della view è variabile. Considerando quindi il numero dei componenti che dobbiamo inserire definiamo un margine superiore e inferiore pari a circa il 5% della dimensione della view:
int spacey = frame.size.height * 0.05;
int spacex = frame.size.width * 0.05;
Mentre alla casella di testo assegnamo il 10%
int textSpace = frame.size.width * 0.1;
Non ci resta quindi che stabilire le 2 dimensioni dello slider, ricordando però gli spazi tra i componenti e il fatto che gli slider sono 3.
int sizex = frame.size.width - (3 * spacex) - textSpace;
int sizey = (frame.size.height - (2 * spacey) ) / 3;
Magari vi sarà tutto più chiaro con questa immagine:

Non ci resta quindi che iniziare ad allocare gli slider. Il codice è praticamente identico per ciascuno slide, cambia soltanto la posizione relativa nella view, esaminiamo quindi il codice per l’inserimento del primo slide:
redSlider = [[UISlider alloc] initWithFrame:CGRectMake(spacex, spacey, sizex, sizey)];
Allochiamo lo slide.
redSlider.minimumValueImage = [UIImage imageNamed:@"red.png"];
Aggiungiamo una immagine, “red.png” come immagine sinistra dello slide.
[redSlider setMinimumTrackImage:[[UIImage imageNamed:@"redSlider.png"] stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0] forState:UIControlStateNormal];
Impostiamo l’immagine redSlider.png come immagine sinistra per la barra di tracking, impostando che i primi 10 pixel devono essere fissi e non stretchabili:
redSlider.minimumValue = 0;
redSlider.maximumValue = 1;
redSlider.value = 0.5;
Impostiamo i valori di minimo, massimo e valore attuale.
redSlider.continuous = TRUE;
Se impostata a TRUE questa proprietà fa si che vengano generati in continuazione eventi “UIControlEventValueChanged”, mentre se impostata a FALSE avviene solo quando lasciamo lo slider.
[redSlider addTarget:self action:@selector(sliderAction) forControlEvents:UIControlEventValueChanged];
Settiamo qual’è la funzione che deve essere eseguita quando lo slide manda il messaggio
UIControlEventValueChanged.
[self addSubview:redSlider];
Aggiungo lo slider alla view.
Molto semplice anche l’aggiunta delle UILabel per visualizzare il valore numerico corrente:
red_text = [[UILabel alloc] initWithFrame:CGRectMake(sizex + 2 * spacex, spacey, textSpace, sizey)];
red_text.textColor = [UIColor whiteColor];
red_text.backgroundColor = [UIColor clearColor];
red_text.font = [UIFont boldSystemFontOfSize:11];
red_text.text = @"0.5";
[self addSubview:red_text];
Il metodo che viene invocato ad ogni cambio di valore è il seguente:
- (void)sliderAction {
red_text.text = [NSString stringWithFormat:@"%.02f",[redSlider value]];
green_text.text = [NSString stringWithFormat:@"%.02f",[greenSlider value]];
blue_text.text = [NSString stringWithFormat:@"%.02f",[blueSlider value]];
[self changeColor:redSlider.value green:greenSlider.value blue:blueSlider.value];
}
aggiorna quindi i valori delle label ed invoca un metodo che si chiama changeColor.
- (void)changeColor:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue{
target.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1];
}
Come vediamo qui viene utilizzata la view “target” nonostante non sia mai stata inizializzata e vengono utilizzati i valori prelevati dagli slider per cambiare il colore.
Questo è possibile perchè la view ci è stata passata come parametro, più precisamente, vediamo in conclusione come usare quanto appena creato, ovvero il codice di una view che vuole istanziare un oggetto di tipo editView:
editView *ed = [[editView alloc] initWithFrame:CGRectMake(50,140, 220, 200)];
[ed setTarget:square];
[self.view addSubview:ed];
Spero il tutorial vi sia utile, viste le diverse tematiche affrontate..
Vi lasciamo con il risultato finale.
Alla prossima!










5 Responses to “T#078 – Creiamo una subView personalizzata da codice (Xcode e Objective-C)”
29 Ottobre 2010
Tweets that mention Creare una View personalizzata da codice (Xcode e Objective-C) | devAPP -- Topsy.com[…] This post was mentioned on Twitter by Rynox, iPadWorld.it and Bubi Devs, devAPP. devAPP said: Creiamo una subView personalizzata da codice (Xcode e Objective-C) http://bit.ly/cvejjP […]
29 Ottobre 2010
AndreaL’avevo fatta io la domanda sul forum, grazie per aver creato il tutorial 🙂
Anche se pochi giorni dopo aver postato la domanda sul forum sono riuscito a creare quello che mi serviva (più o meno ho eseguito gli stessi passi mostrati in questo tutorial)!
15 Febbraio 2011
AnnaUn interessante tutorial, al di là dell’obiettivo specifico offre elementi utili anche per altro. Avrei un quesito. Sono in fase di progettazione di una applicazione che dovrebbe prevedere l’uso di diverse view e l’integrazione di mappe, di presentazione di foto, di tableview, browser, notifiche push. Mi chiedo: per integrarle in un unica applicazione qual’è il tipo di template più adeguato? Ho cominciato ad utilizzare la View-Based Application, perchè essendo vuota non pone limiti, faccio bene? Grazie!
22 Maggio 2011
VinceN3ilCiao,intanto facci i complimenti per questi utilissimi tutorial,poi vorrei fare una domanda,probabilmente sciocca,ma sono alle primissime armi:non riesco a capire l’ultima parti di codice:
editView *ed = [[editView alloc] initWithFrame:CGRectMake(50,140, 220, 200)];
[ed setTarget:square];
[self.view addSubview:ed];
e non capisco nemmeno *_* dov’è che va inserito.
Approfitto inoltre per chiedere anche un altra cosina,come è possibile personalizzare, creare/disegnare,per esempio slides o button.?!o piu genericamente disegnare/creare dettagli grafici al di fuori di quelli inseriti da Apple?!
Grazie.
Un saluto
Vince.
22 Maggio 2011
IgnaziocQuella parte di codice è quella realiva all’utilizzo di questa view.
serve per istanziarla, impostare il suo target (la view che cambierà colore) e poi per aggiungerla nello stack delle view.
I controlli sono personalizzabili c’è un esempio di apple cerca “catalog” su apple developer.
Per gli UIButton puoi inserire delle immagini in modo che il pulsante appaia come vuoi tu, per gli slider puoi cambiare le tre immagini che lo compongono (la parte bianca, quella blu e la palina al centro..)