{"id":4812,"date":"2010-10-29T12:32:39","date_gmt":"2010-10-29T10:32:39","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=4812"},"modified":"2010-10-29T12:32:39","modified_gmt":"2010-10-29T10:32:39","slug":"t078-creiamo-una-subview-personalizzata-da-codice-xcode-e-objective-c","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/t078-creiamo-una-subview-personalizzata-da-codice-xcode-e-objective-c\/","title":{"rendered":"T#078 &#8211; Creiamo una subView personalizzata da codice (Xcode e Objective-C)"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-01.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-01.jpg\" alt=\"t078-view-personalizzata-con-xcode-objective-c-01\" title=\"t078-view-personalizzata-con-xcode-objective-c-01\" width=\"150\" height=\"261\" class=\"alignleft size-full wp-image-4925\" \/><\/a> Rieccoci con un breve tutorial! Oggi vogliamo rispondere ad una domanda che ci \u00e8 stata fatta diverse volte <a href=\"http:\/\/www.devapp.it\/wordpress\/forum\/showthread.php?253-Come-si-crea&#038;highlight=subview\" target=\"_blank\">sul nostro forum<\/a>: &#8220;Come riuscire ad implementare nella nostra applicazione iPhone una subView personalizzata simile a questa mostrata in figura qui a lato?&#8221;<\/p>\n<p>Come spesso accade, non c&#8217;\u00e8 un solo modo per realizzare una view simile per aspetto e funzionalit\u00e0 a quella in foto, ciascun programmatore \u00e8 libero di esprimersi come meglio crede e, a meno di profondi errori, non c&#8217;\u00e8 un metodo giusto ed uno sbagliato.<br \/>\nIo personalmente amo generalizzare e mi piace scrivere codice, magari pi\u00f9 prolisso, ma che pu\u00f2 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.<\/p>\n<p>A dire il vero questo codice non \u00e8 &#8220;completamente&#8221; generalizzato, in quanto gli slider eseguono una funzione predefinita, in pratica possiamo riutilizzare s\u00ec 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)<!--more--><\/p>\n<h4>Creiamo un nuovo progetto<\/h4>\n<p>Iniziamo quindi con il creare un nuovo progetto, per seguire questo tutorial pu\u00f2 andare bene anche un template di tipo &#8220;view based application&#8221;. Creato il nostro progetto aggiungiamo una nuova classe cliccando sul men\u00f9 file -> new file e scegliendo l&#8217;icona di &#8220;objective-c Class&#8221;. Selezioniamo &#8220;UIview&#8221; dalla casella &#8220;Subclass of&#8221; e clicchiamo su next. Inseriamo un nome significativo e clicciamo su &#8220;finish&#8221;. Io in un volo di fantasia l&#8217;ho chiamata &#8220;editView&#8221;.<\/p>\n<p>Questa che abbiamo creato \u00e8 quindi una nuova classe che eredita dalla classe UIView. Se avete gi\u00e0 letto qualcosa su OOP vi sar\u00e0 gi\u00e0 chiaro che il grosso del lavoro \u00e8 gi\u00e0 stato fatto, tutti i metodi e le propriet\u00e0 utilizzabili su un&#8217;oggetto di tipo UIView sono gi\u00e0 automaticamente utilizzabili anche sulla nostra classe, non ci resta che personalizzarli.<\/p>\n<h4>Importiamo e dichiariamo gli elementi necessari<\/h4>\n<p>Visualizziamo il file editView.h che abbiamo creato ed aggiungiamo in testa, la direttiva<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#import <QuartzCore\/QuartzCore.h>\r\n<\/pre>\n<p>Quartz \u00e8 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.<br \/>\nPurtoppo la sola direttiva non \u00e8 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 &#8220;frameworks&#8221; e selezioniamo &#8220;add -> existing framework&#8221; e aggiungiamo quindi &#8220;QuartzCore&#8221;<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-02.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-02.jpg\" alt=\"t078-view-personalizzata-con-xcode-objective-c-02\" title=\"t078-view-personalizzata-con-xcode-objective-c-02\" width=\"449\" height=\"569\" class=\"aligncenter size-full wp-image-4926\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-02.jpg 449w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-02-236x300.jpg 236w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-02-118x150.jpg 118w\" sizes=\"auto, (max-width: 449px) 100vw, 449px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Aggiungiamo quindi le propriet\u00e0 che servono alla nostra view, io ho aggiunto queste:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@interface editView : UIView {\r\n\tUISlider *redSlider;\r\n\tUISlider *greenSlider;\r\n\tUISlider *blueSlider;\r\n\tUILabel *red_text;\r\n\tUILabel *green_text;\r\n\tUILabel *blue_text;\r\n\tUIView *target;\r\n}\r\n\r\n@property (nonatomic, retain) UIView *target;\r\n@property (nonatomic, retain) UISlider *redSlider;\r\n@property (nonatomic, retain) UISlider *greenSlider;\r\n@property (nonatomic, retain) UISlider *blueSlider;\r\n<\/pre>\n<p>Gli slider serviranno per modificare il colore della view specificata, mentre le label mostreranno il valore dello slider.<br \/>\nE la view &#8220;target&#8221; cos&#8217;\u00e8? Spero si capisca leggendo il codice, perch\u00e9 non \u00e8 facile spiegarlo a parole \ud83d\ude42  in breve la view &#8220;target&#8221; fa da segnaposto (come i parametri formali delle funzioni) e viene correttamente valorizzata od ogni utilizzo della view.<\/p>\n<h4>Passiamo all&#8217;implementazione<\/h4>\n<p>Nel file editView.m troviamo alcuni metodi gi\u00e0 scritti per noi, Xcode li ha aggiunti per semplificarci la vita.<br \/>\nCerchiamo e modificichiamo quindi il metodo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (id)initWithFrame:(CGRect)frame\r\n<\/pre>\n<p>per far si che venga generata la view per come la desieriamo.<\/p>\n<p>Ho deciso di non attribuire una dimensione fissa alla view, questo complica le cose ma ci torner\u00e0 utile se vogliamo utilizzarla in un altro progetto in cui lo spazio a disposizione \u00e8 diverso. Ho limitato per\u00f2 la dimensione ad almeno 200px x 200px e l&#8217;ho fatto con un metodo un p\u00f2 strano, utilizzando questo codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (id)initWithFrame:(CGRect)frame {\r\n\tassert(frame.size.width &gt;= 200);\r\n\tassert(frame.size.height &gt;= 200);\r\n\t[...]\r\n<\/pre>\n<p>Ovviamente l&#8217;ho fatto a solo scopo didattico, perch\u00e9 la funzione assert genera una eccezione sel il suo parametro \u00e8 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\u00e8 nell&#8217;applicazione finale dovr\u00e0 essere sostituita con una reale gestione dell&#8217;errore.<\/p>\n<p>Il codice prosegue con:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nif ((self = [super initWithFrame:frame])) {\r\n<\/pre>\n<p>Invochiamo il metodo initiWithFrame della superclasse e ci assicuriamo che non restituisca null.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nself.layer.cornerRadius\t        = kDefaultCornerRadius;\r\nself.backgroundColor\t\t= kDefaultRectColor;\r\nself.alpha\t\t\t\t= kDefaultAlphaValue;\r\n[self.layer setBorderColor:[[UIColor whiteColor] CGColor]];\r\n[self.layer setBorderWidth: 2.0];\r\n<\/pre>\n<p>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.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#define kDefaultRectColor          [UIColor blackColor]\r\n#define kDefaultCornerRadius      20.0\r\n#define kDefaultAlphaValue\t     .8\r\n<\/pre>\n<p>A questo punto bisogna iniziare a creare la view via codice, ma non possiamo utilizzare riferimenti statici per gli slider, perch\u00e8 abbiamo detto che la dimensione della view \u00e8 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:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nint spacey = frame.size.height * 0.05;\r\nint spacex = frame.size.width * 0.05;\r\n<\/pre>\n<p>Mentre alla casella di testo assegnamo il 10%<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nint textSpace = frame.size.width * 0.1;\r\n<\/pre>\n<p>Non ci resta quindi che stabilire le 2 dimensioni dello slider, ricordando per\u00f2 gli spazi tra i componenti e il fatto che gli slider sono 3.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nint sizex = frame.size.width - (3 * spacex) - textSpace;\r\nint sizey = (frame.size.height - (2 * spacey) ) \/ 3;\r\n<\/pre>\n<p>Magari vi sar\u00e0 tutto pi\u00f9 chiaro con questa immagine:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-03.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-03.jpg\" alt=\"t078-view-personalizzata-con-xcode-objective-c-03\" title=\"t078-view-personalizzata-con-xcode-objective-c-03\" width=\"449\" height=\"452\" class=\"aligncenter size-full wp-image-4924\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-03.jpg 449w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-03-150x150.jpg 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-03-298x300.jpg 298w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-03-92x92.jpg 92w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-03-64x64.jpg 64w\" sizes=\"auto, (max-width: 449px) 100vw, 449px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Non ci resta quindi che iniziare ad allocare gli slider. Il codice \u00e8 praticamente identico per ciascuno slide, cambia soltanto la posizione relativa nella view, esaminiamo quindi il codice per l&#8217;inserimento del primo slide:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nredSlider = [[UISlider alloc] initWithFrame:CGRectMake(spacex,  spacey, sizex, sizey)];\r\n<\/pre>\n<p>Allochiamo lo slide.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nredSlider.minimumValueImage = [UIImage imageNamed:@\"red.png\"];\r\n<\/pre>\n<p>Aggiungiamo una immagine, &#8220;red.png&#8221; come immagine sinistra dello slide.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[redSlider setMinimumTrackImage:[[UIImage imageNamed:@\"redSlider.png\"] stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0] forState:UIControlStateNormal];\r\n<\/pre>\n<p>Impostiamo l&#8217;immagine redSlider.png come immagine sinistra per la barra di tracking, impostando che i primi 10 pixel devono essere fissi e non stretchabili:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nredSlider.minimumValue = 0;\r\nredSlider.maximumValue = 1;\r\nredSlider.value = 0.5;\r\nImpostiamo i valori di minimo, massimo e valore attuale.\r\nredSlider.continuous = TRUE;\r\n<\/pre>\n<p>Se impostata a TRUE questa propriet\u00e0 fa si che vengano generati in continuazione eventi &#8220;UIControlEventValueChanged&#8221;, mentre se impostata a FALSE avviene solo quando lasciamo lo slider.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[redSlider addTarget:self action:@selector(sliderAction) forControlEvents:UIControlEventValueChanged];\r\n<\/pre>\n<p>Settiamo qual&#8217;\u00e8 la funzione che deve essere eseguita quando lo slide manda il messaggio <\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nUIControlEventValueChanged.\r\n[self addSubview:redSlider];\r\n<\/pre>\n<p>Aggiungo lo slider alla view.<\/p>\n<p>Molto semplice anche l&#8217;aggiunta delle UILabel per visualizzare il valore numerico corrente:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nred_text = [[UILabel alloc] initWithFrame:CGRectMake(sizex +  2 * spacex, spacey, textSpace, sizey)];\r\nred_text.textColor = [UIColor whiteColor];\r\nred_text.backgroundColor = [UIColor clearColor];\r\nred_text.font = [UIFont boldSystemFontOfSize:11];\r\nred_text.text = @\"0.5\";\r\n[self addSubview:red_text];\r\n<\/pre>\n<p>Il metodo che viene invocato ad ogni cambio di valore \u00e8 il seguente:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)sliderAction {\r\n\tred_text.text = [NSString stringWithFormat:@\"%.02f\",[redSlider value]];\r\n\tgreen_text.text = [NSString stringWithFormat:@\"%.02f\",[greenSlider value]];\r\n\tblue_text.text = [NSString stringWithFormat:@\"%.02f\",[blueSlider value]];\r\n\t[self changeColor:redSlider.value green:greenSlider.value blue:blueSlider.value];\r\n\t\r\n}\r\n<\/pre>\n<p>aggiorna quindi i valori delle label ed invoca un metodo che si chiama changeColor.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)changeColor:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue{\r\n\ttarget.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1];\r\n}\r\n<\/pre>\n<p>Come vediamo qui viene utilizzata la view &#8220;target&#8221; nonostante non sia mai stata inizializzata e vengono utilizzati i valori prelevati dagli slider per cambiare il colore.<\/p>\n<p>Questo \u00e8 possibile perch\u00e8 la view ci \u00e8 stata passata come parametro, pi\u00f9 precisamente, vediamo in conclusione come usare quanto appena creato, ovvero il codice di una view che vuole istanziare un oggetto di tipo editView:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\neditView *ed = [[editView alloc] initWithFrame:CGRectMake(50,140, 220, 200)];\r\n[ed setTarget:square];\r\n[self.view addSubview:ed];\r\n<\/pre>\n<p>Spero il tutorial vi sia utile, viste le diverse tematiche affrontate..<\/p>\n<p>Vi lasciamo con il risultato finale.<br \/>\nAlla prossima!<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-01.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-01.jpg\" alt=\"t078-view-personalizzata-con-xcode-objective-c-01\" title=\"t078-view-personalizzata-con-xcode-objective-c-01\" width=\"386\" height=\"742\" class=\"aligncenter size-full wp-image-4925\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-01.jpg 386w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-01-156x300.jpg 156w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/10\/t078-view-personalizzata-con-xcode-objective-c-01-78x150.jpg 78w\" sizes=\"auto, (max-width: 386px) 100vw, 386px\" \/><\/a><br \/>\n<\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Rieccoci con un breve tutorial! Oggi vogliamo rispondere ad una domanda che ci \u00e8 stata fatta diverse&#8230;<\/p>\n","protected":false},"author":53,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[241,465,439,466,279,63],"class_list":["post-4812","post","type-post","status-publish","format-standard","hentry","category-tutorial-pratici","tag-ignazio-calo","tag-initwithframe","tag-quartzcore","tag-subview","tag-uislider","tag-uiview"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/4812","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=4812"}],"version-history":[{"count":24,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/4812\/revisions"}],"predecessor-version":[{"id":4937,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/4812\/revisions\/4937"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=4812"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=4812"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=4812"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}