{"id":2727,"date":"2010-03-27T16:14:16","date_gmt":"2010-03-27T15:14:16","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=2727"},"modified":"2010-03-27T16:20:00","modified_gmt":"2010-03-27T15:20:00","slug":"t028-utilizzo-del-mapkit-parte-1-zoom-e-annotation-view-personalizzate","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/t028-utilizzo-del-mapkit-parte-1-zoom-e-annotation-view-personalizzate\/","title":{"rendered":"T#028 &#8211; Utilizzo del MapKit (parte 1): Zoom e Annotation View personalizzate"},"content":{"rendered":"<p>Eccomi al mio primo tutorial su DevAPP in cui vedremo i principali elementi che ci mette a disposizione il <em>MapKit<\/em>. In questa prima parte vedremo come zoommare sulla posizione dell&#8217;utente quando vengono acquisite le coordinate GPS e come aggiungere delle annotation view sulla nostra mappa. Premetto che io non ho l&#8217;abitudine di usare Interface Builder e che tutte le view che andremo ad utilizzare verranno create pragmaticamente.<!--more--><\/p>\n<h4>Setup<\/h4>\n<p>Cominciamo col creare un nuovo progetto\u00a0<em>Window-Based <\/em>in modo che vengano automaticamente generati solamente la window e l&#8217;application delegate. Una volta fatto ci\u00f2 la prima cosa che dobbiamo fare \u00e8 importare il framework\u00a0<em>MapKit<\/em>: facciamo click secondario sul gruppo framework in\u00a0<em>Groups &amp; Files<\/em>,\u00a0selezionando\u00a0<em>Add &#8211; Existing framework<\/em> e scegliamo\u00a0<em>MapKit.framework<\/em>. Importiamolo ora nel file\u00a0<em>nomeprogetto_prefix.pch<\/em> che trovate nel gruppo\u00a0<em>Other Sources<\/em> in modo che tutte le classi che andremo a creare potranno utilizzarlo. Il prefix header alla fine dovr\u00e0 essere cos\u00ec:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#ifdef __OBJC__\r\n    #import &lt;Foundation\/Foundation.h&gt;\r\n    #import &lt;UIKit\/UIKit.h&gt;\r\n    #import &lt;MapKit\/MapKit.h&gt;\r\n#endif\r\n<\/pre>\n<h4>Creazione della map view<\/h4>\n<p>A questo punto ci ritroviamo con un&#8217;applicazione pronta ad utilizzare le mappe. Creiamo ora un nuovo\u00a0<em>UIViewController<\/em> che chiameremo\u00a0<em>MapViewController<\/em>. Cominciamo con l&#8217;aprire il file\u00a0<em>MapViewController.h<\/em> e modifichiamolo in modo da adottare il protocollo\u00a0<em>MKMapViewDelegate<\/em>.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@interface MapViewController : UIViewController &lt;MKMapViewDelegate&gt;\r\n\r\n@end\r\n<\/pre>\n<p>Apriamo invece ora il file\u00a0<em>MapViewController.m<\/em> e ridefiniamo la funzione\u00a0<em>loadView<\/em> per poter creare la nostra map view.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)loadView {\r\n    self.title = @\"Mappa\";\r\n    MKMapView *map= [[[MKMapView alloc] init] autorelease];\r\n    map.delegate = self;\r\n    map.showsUserLocation = YES;\r\n    self.view = map;\r\n}\r\n<\/pre>\n<p>In questo metodo allochiamo una nuova map view con abilitata la visualizzazione della posizione dell&#8217;utente, gli settiamo il controller stesso come delegate e visualizziamo la mappa assegnandola alla view del controller.<\/p>\n<p>Se ora compiliamo ed eseguiamo l&#8217;applicazione l&#8217;unica cosa che vedremo sar\u00e0 una schermata bianca (il colore di default della window). Questo perch\u00e9 non abbiamo ancora aggiunto questa vista nella finestra. Per far ci\u00f2 apriamo il file di implementazione dell&#8217;application delegate e modifichiamo la funzione\u00a0<em>applicationDidFinishLaunching<\/em> come segue:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)applicationDidFinishLaunching:(UIApplication *)application {\r\n    MapViewController *rootViewController = [[[MapViewController alloc] init] autorelease];\r\n    UINavigationController navController = [[UINavigationController alloc] initWithRootViewController:rootViewController];\r\n    [window addSubview:navController.view];\r\n    [window makeKeyAndVisible];\r\n}\r\n<\/pre>\n<p>Quello che facciamo \u00e8 semplicemente creare un\u00a0<em>UINavigationController<\/em> (il perch\u00e9 lo capiremo quando parleremo delle annotation) usando il nostro\u00a0<em>MapViewController<\/em> come root controller e visualizzare la sua view nella finestra.<\/p>\n<p>Se ora compiliamo vedremo la mappa e, dopo un breve lasso di tempo, il puntino blu della nostra posizione a Cupertino (se siamo sul simulatore).<\/p>\n<p><center><\/p>\n<p style=\"text-align: center;\"><img decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/03\/T028-img1.png\" alt=\"Immagine 1\" \/><\/p>\n<p><\/center><\/p>\n<h4>Zoommiamo sulla posizione dell&#8217;utente<\/h4>\n<p>Per far questo dobbiamo ridefinire un metodo del protocollo\u00a0<em>MKMapViewDelegate<\/em>. Riapriamo quindi il file\u00a0<em>MapViewController<\/em> e aggiungiamo il seguente metodo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {\r\n    for (MKAnnotationView *annotationView in views) {\r\n        if (annotationView.annotation == mapView.userLocation) {\r\n            MKCoordinateSpan span = MKCoordinateSpanMake(0.3, 0.3);\r\n            MKCoordinateRegion region = MKCoordinateRegionMake(mapView.userLocation.coordinate, span);\r\n            [mapView setRegion:region animated:YES];\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Questo metodo viene chiamato ogniqualvolta viene aggiunta una annotation alla mappa e quindi anche quando viene aggiunto il pallino blu relativo alla posizione dell&#8217;utente. Il codice scritto non fa altro che cercare tra le annotation view aggiunte se \u00e8 presente quella relativa alla posizione dell&#8217;utente (<em>mapView.userLocation<\/em>). La regione che deve visualizzare la mappa viene settata in modo che in modo che sia centrata sulle coordinate dell&#8217;utente e in modo che la distanza nord-sud o ovest-est (dipende dal fatto che la mappa sia in landscape o portrait) sia di 0.3 gradi (stando alla documentazione 1 grado \u00e8 circa 111km). Con la funzione\u00a0<em>setRegion:animated <\/em>modifichiamo l&#8217;area visualizzata dalla mappa tramite un&#8217;animazione.<\/p>\n<p>Se ora compiliamo ed eseguiamo l&#8217;applicativo vediamo che, quando viene acquisita la posizione dell&#8217;utente, la view viene modificata tramite un&#8217;animazione.<\/p>\n<p><center><\/p>\n<p style=\"text-align: center;\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/03\/T028-img2.png\" alt=\"Immagine 2\" width=\"321\" height=\"618\" \/><\/p>\n<p><\/center><\/p>\n<h4>Aggiunta di una annotation view personalizzata<\/h4>\n<p>Innanzitutto dobbiamo avere una annotation (ovvero un oggetto conforme al protocollo\u00a0<em>MKAnnotation<\/em>)\u00a0da visualizzare. Creiamo perci\u00f2 una nuova classe (io l&#8217;ho chiamata\u00a0<em>GoogleHQAnnotation<\/em>) che estende\u00a0<em>NSObject<\/em> a cui facciamo adottare il protocollo <em>MKAnnotation<\/em>. Per esempio io ho creato l&#8217;annotazione relativa alla sede di Google a Mountain View in California. Modifichiamo il file <em>.h<\/em> in modo di avere il seguente codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@interface GoogleHQAnnotation : NSObject &lt;MKAnnotation&gt;  {\r\n\tCLLocationCoordinate2D coordinate;\r\n}\r\n\r\n@end\r\n<\/pre>\n<p>L&#8217;attributo\u00a0<em>coordinate<\/em> \u00e8 un attributo richiesto dal protocollo\u00a0<em>MKAnnotation<\/em> e siamo quindi obbligati a dichiararlo. Passiamo ora al file di implementazione:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#import \"GoogleHQAnnotation.h\"\r\n\r\n@implementation GoogleHQAnnotation\r\n\r\n- (id)init {\r\n    coordinate.longitude = -122.084095;\r\n    coordinate.latitude = 37.422006;\r\n    return [super init];\r\n}\r\n\r\n@synthesize coordinate;\r\n\r\n- (NSString *)title {\r\n    return @\"Google HQ\";\r\n}\r\n\r\n- (NSString *)subtitle {\r\n    return @\"(650) 253-0000\u200e\";\r\n}\r\n\r\n@end\r\n<\/pre>\n<p>Si tratta di un semplice file di implementazione dove nella ridefinizione del metodo\u00a0<em>init<\/em> ci limitiamo a settare le coordinate che puntano la sede di Google e che implementa i metodi richiesti dal protocollo (ovvero\u00a0<em>title<\/em>,\u00a0<em>subtitle<\/em> e\u00a0<em>coordinate<\/em>). L&#8217;unica cosa strana \u00e8 che abbiamo utilizzato la direttiva\u00a0<em>@synthesize<\/em> senza aver dichiarato la property nel file di interfaccia. Questo non \u00e8 un errore in quanto, adottando il protocollo\u00a0<em>MkAnnotation<\/em> ereditiamo pure la propriet\u00e0 dichiarata come\u00a0<em>@property (nonatomic, readonly) CLLocationCoordinate2D coordinate<\/em> in esso definita.<\/p>\n<p>Torniamo al\u00a0<em>MapViewController<\/em>. Dobbiamo aggiungere l&#8217;annotazione alla map view. Possiamo quindi aggiungerla, per esempio, in fase di creazione nella\u00a0<em>loadView<\/em> andando ad aggiungere la seguente riga di codice alla fine della funzione:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[map addAnnotation:[[[GoogleHQAnnotation alloc] init] autorelease]];\r\n<\/pre>\n<p>ricordandoci di importare il file<em> .h<\/em> della classe\u00a0<em>GoogleHQAnnotation<\/em>.<\/p>\n<p>A questo punto se eseguiamo l&#8217;applicativo gi\u00e0 verr\u00e0 creata la annotation view di default, ma noi ne vogliamo una personalizzata. Dobbiamo quindi ridefinire il metodo\u00a0<em>mapView:viewForAnnotation:<\/em> ereditato dal protocollo\u00a0<em>MKMapViewDelegate<\/em>. Questo metodo \u00e8 quello a cui \u00e8 delegata la creazione delle annotation view di ogni annotation. Lo implementeremo nel seguente modo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation {\r\n    if (annotation == mapView.userLocation) {\r\n        return nil;\r\n    }\r\n    MKPinAnnotationView *pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@\"Pin\"] autorelease];\r\n    pinView.pinColor = MKPinAnnotationColorPurple;\r\n    pinView.canShowCallout = YES;\r\n    pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];\r\n    pinView.animatesDrop = YES;\r\n    return pinView;\r\n}\r\n<\/pre>\n<p>Analizziamo ora il codice scritto. Nel blocco\u00a0<em>if<\/em> controlliamo se l&#8217;annotazione di cui dobbiamo creare la view \u00e8 quella relativa alla posizione dell&#8217;utente. In tal caso diamo come valore di ritorno\u00a0<em>nil<\/em> che serve a far capire al sistema che per quella annotazione deve usare la annotation view di default. In caso contrario creiamo un pin da visualizzare avente le seguenti caratteristiche:<\/p>\n<ul>\n<li>Colore viola (<em>pinView.pinColor = MKPinAnnotationColorPurple<\/em>)<\/li>\n<li>Permette di visualizzare il callaut, ovvero il fumetto che appare quando tappate il pin (<em>pinView.canShowCallout = YES<\/em>)<\/li>\n<li>Ha uno disclosure button sulla parte destra del callout (<em>pinView.rightCalloutAccessoryView = &#8230;<\/em>)<\/li>\n<li>Appare tramite un&#8217;animazione (<em>pinView.animatesDrop = YES<\/em>)<\/li>\n<\/ul>\n<p>La funzione termina con una\u00a0<em>return pinView<\/em> che serve a far capire al sistema che quella annotazione verr\u00e0 rappresentata sulla mappa dalla annotation view che abbiamo creato noi e non da quella di default.<\/p>\n<p>Se ora compiliamo ed eseguiamo l&#8217;applicazione vedremo il nostro bel pin viola e se lo tappiamo apparir\u00e0 il callout con titolo e sottotitolo. Ma c&#8217;\u00e8 ancora qualcosa che manca. Infatti possiamo premere il disclosure button tutte le volte che vogliamo ma non accadr\u00e0 niente. Per gestire questo evento dobbiamo ridefinire un metodo ereditato dal protocollo <em>MKMapViewDelegate<\/em> che viene invocato ogni volta che viene tappato un button presente in un qualsiasi callout. Aggiungiamo quindi il seguente codice al <em>MapViewContoller<\/em>:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {\r\n\t[self.navigationController pushViewController:[[[UIViewController alloc] init] autorelease] animated:YES];\r\n}\r\n<\/pre>\n<p>In pratica cos\u00ec facendo, quando premeremo il disclosure button verremo reindirizzati ad una nuova vista che sar\u00e0 la base di partenza per la seconda parte tutorial.<\/p>\n<p><center><\/p>\n<p style=\"text-align: center;\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/03\/T028_img3.png\" alt=\"Immagine 3\" width=\"321\" height=\"618\" \/><\/p>\n<p><\/center><\/p>\n<p>Se avete bisogno del codice lo potete tranquillamente scaricare comprensivo di commenti da <a href=\"http:\/\/code.google.com\/p\/devapptutorials\/\" target=\"blank\">google code<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Eccomi al mio primo tutorial su DevAPP in cui vedremo i principali elementi che ci mette a&#8230;<\/p>\n","protected":false},"author":181,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[157,155,154,158,156],"class_list":["post-2727","post","type-post","status-publish","format-standard","hentry","category-tutorial-pratici","tag-annotation","tag-kit","tag-map","tag-pin","tag-zoom"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/2727","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\/181"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=2727"}],"version-history":[{"count":40,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/2727\/revisions"}],"predecessor-version":[{"id":2774,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/2727\/revisions\/2774"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=2727"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=2727"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=2727"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}