{"id":3133,"date":"2010-05-05T09:30:17","date_gmt":"2010-05-05T07:30:17","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=3133"},"modified":"2010-05-04T17:37:50","modified_gmt":"2010-05-04T15:37:50","slug":"t038-utilizzo-del-mapkit-parte-2-annotation-view-calcolo-della-distanza-e-reverse-geocoding","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/t038-utilizzo-del-mapkit-parte-2-annotation-view-calcolo-della-distanza-e-reverse-geocoding\/","title":{"rendered":"T#038 &#8211; Utilizzo del MapKit (parte 2): Annotation view calcolo della distanza e reverse geocoding"},"content":{"rendered":"<p>Con molto pi\u00f9 ritardo di quello che avevo previsto, ecco la seconda parte del tutorial riguardante il MapKit. Non perdiamoci in convenevoli e veniamo subito al sodo.<\/p>\n<h4>Annotation view con immagine personalizzata<\/h4>\n<p>Riprendiamo il codice scritto l&#8217;altra volta. Eravamo arrivati a creare una annotation view che visualizzava un pin relativo alla sede di Google a Mountain View. Vogliamo ora sostituire il pin con un&#8217;immagine personalizzata. Dopo aver scelto quindi l&#8217;immagine che pi\u00f9 ci aggrada e averla aggiunta tra le risorse dell&#8217;applicazione, possiamo modificare il codice che avevamo scritto nel metodo <em>mapView:viewForAnnotation:<\/em> modificandolo come segue:<!--more--><\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id &lt;MKAnnotation&gt;)annotation {\r\n    if (annotation == mapView.userLocation) {\r\n        return nil;\r\n    }\r\n    MKAnnotationView *annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@\"Pin\"] autorelease];\r\n    annotationView.image = [UIImage imageNamed:@\"google.png\"];\r\n    annotationView.canShowCallout = YES;\r\n    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];\r\n    return annotationView;\r\n}\r\n<\/pre>\n<p>Come possiamo notare la sostanziale differenza rispetto al codice scritto precedentemente sta nel fatto che non usiamo pi\u00f9\u00a0<em>MKPinAnnotationView<\/em> ma utilizziamo una classe pi\u00f9 generica (ad essere precisi la superclasse di <em>MKPinAnnotationView<\/em>) che ci permette di utilizzare un&#8217;immagine a nostra scelta caricandola dalle risorse dell&#8217;applicazione\u00a0(in questo caso <em>google.png<\/em>) al posto del solito pin. Tutto questo lo facciamo con le righe 5 e 6 del precedente codice, mentre tutte le altre istruzioni sono gi\u00e0 state spiegate nel <a href=\"http:\/\/www.devapp.it\/wordpress\/t028-utilizzo-del-mapkit-parte-1-zoom-e-annotation-view-personalizzate.html\" target=\"_blank\">tutorial precedente.<\/a><\/p>\n<p><center><\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/05\/MK02_1.png\" alt=\"Annotation view con immagine personalizzata\" width=\"321\" height=\"618\" \/><\/p>\n<p><\/center><\/p>\n<h4>Cacolo della distanza tra due punti e reverse geocoding<\/h4>\n<p>La prima cosa che dobbiamo effettuare \u00e8 importare il framework che ci permette di effettuare questa operazione. Apriamo quindi il file prefix (in XCode lo trovate nel gruppo <em>Other Sources<\/em>) e modifichiamolo in modo da importare il framework <em>CoreLocation<\/em>. Alle fine il file dovrebbe presentarsi come segue:<\/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;CoreLocation\/CoreLocation.h&gt;\r\n    #import &lt;MapKit\/MapKit.h&gt;\r\n#endif\r\n<\/pre>\n<p>Andiamo ora a creare un nuovo controller (io l&#8217;ho chiamato <em>InfoViewController<\/em>) \u00a0che si occuper\u00e0 di gestire la vista che verr\u00e0 visualizzata quando premiamo sul disclosure button dell&#8217;immagine precedente.<\/p>\n<p>Cominciamo subito con l&#8217;aprire il file <em>.h<\/em> che editeremo come segue:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@interface InfoViewController : UIViewController &lt;MKReverseGeocoderDelegate&gt; {\r\n    CLLocationDistance distance;\r\n    MKReverseGeocoder *reverseGeocoder;\r\n}\r\n\r\n- (id)initWithUserLocation:(CLLocation *)userLocation annotation:(id &lt;MKAnnotation&gt;)annotation;\r\n\r\n@end\r\n<\/pre>\n<p>Qui abbiamo abbiamo semplicemente aggiunto una variabile di tipo <em>CLLocationDistance<\/em> (che in sostanza \u00e8 un\u00a0<em>double<\/em>) nella quale memorizzeremo la distanza che c&#8217;\u00e8 tra l&#8217;utente e la locazione selezionata e un metodo <em>init<\/em> che ci permette di passare al controller la posizione dell&#8217;utente e l&#8217;annotazione su cui vogliamo lavorare. Dichiariamo inoltre un puntatore ad un geocoder e rendiamo la classe conforme al protocollo <em>MKReverseGeocoderDelegate<\/em>. Questo, come vedremo, ci permetter\u00e0 di venire a conoscenza dell&#8217;indirizzo della sede di Google.<\/p>\n<p>Passiamo ora all&#8217;implementazione di questa classe. Andiamo perci\u00f2 a scrivere il metodi <em>initWithUserLocation:annotation:<\/em> definito nel file <em>.h<\/em> e ridefinendo la <em>loadView<\/em>.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (id)initWithUserLocation:(CLLocation *)userLocation annotation:(id &lt;MKAnnotation&gt;)annotation {\r\n    self = [super init];\r\n    self.title = annotation.title;\r\n    CLLocation *location = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];\r\n    distance = [userLocation getDistanceFrom:location];\r\n    reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:annotation.coordinate];\r\n    reverseGeocoder.delegate = self;\r\n    return self;\r\n}\r\n\r\n- (void)loadView {\r\n    [super loadView];\r\n    UILabel *distanceLabel = [[[UILabel alloc] initWithFrame:CGRectMake(5, 0, 310, 24)] autorelease];\r\n    distanceLabel.text = [NSString stringWithFormat:@\"Distanza in metri: %.0f\", distance];\r\n    [self.view addSubview:distanceLabel];\r\n}\r\n<\/pre>\n<p>Quello che facciamo nel metodo <em>initWithUserLocation:annotation:<\/em> non \u00e8 altro che il calcolo della distanza tra la posizione dell&#8217;utente e le coordinate relative all&#8217;annotazione (righe 4 e 5) e di inizializzare il geocoder (righe 6 e 7). Per effettuare la prima operazione ci avvaliamo del metodo <em>getDistanceFrom: <\/em>di <em>CLLocation <\/em>(attenti per\u00f2 che dalla 3.2 il metodo risulta deprecato e quindi al suo posto bisogna invocare\u00a0<em>distanceFromLocation:<\/em>), mentre per inizializzare il geocoder ci basta \u00a0passargli le coordinate di cui vogliamo sapere l&#8217;indirizzo e settargli il delegate.<\/p>\n<p>Nel <em>loadView<\/em> ci limitiamo a visualizzare in label la distanza calcolata.<\/p>\n<p>Per avviare il geocoding basta semplicemente usare il metodo <em>start<\/em>, lo andiamo quindi ad aggiungere ridefinendo la <em>viewDidLoad<\/em>.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)viewDidLoad {\r\n    [reverseGeocoder start];\r\n}\r\n<\/pre>\n<p>Ora ci manca solo l&#8217;implementazione dei metodi per conformarci al protocollo <em>MKReverseGeocoderDelegate<\/em>. Sono solamente due metodi: uno verr\u00e0 chiamato quando il geocoding termina con successo, l&#8217;altro quando fallisce.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {\r\n    NSDictionary *addressData = placemark.addressDictionary;\r\n    CGFloat y = 50;\r\n    for (NSString *key in [addressData allKeys]) {\r\n        if ([key compare:@\"FormattedAddressLines\"] != NSOrderedSame) {\r\n            UILabel *newRow = [[[UILabel alloc] initWithFrame:CGRectMake(5, y, 310, 24)] autorelease];\r\n            newRow.text = [NSString stringWithFormat:@\"%@: %@\", key, [addressData objectForKey:key]];\r\n            [self.view addSubview:newRow];\r\n            y += 24;\r\n        }\r\n    }\r\n}\r\n\r\n- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error {\r\n\tUILabel *geocoderFail = [[[UILabel alloc] initWithFrame:CGRectMake(5, 50, 310, 24)] autorelease];\r\n\tgeocoderFail.text = @\"Reverse geocoding fallito\";\r\n\t[self.view addSubview:geocoderFail];\r\n}\r\n<\/pre>\n<p>Nel primo metodo (geocoding terminato con successo) visualizziamo in delle labels tutte le informazioni legate alle coordinate che abbiamo passato al geocoder (indirizzo, citt\u00e0, nazione, &#8230;), mentre nel caso fallisca ci limitiamo a visualizzare una label che ci informi di ci\u00f2.<\/p>\n<p>Ora \u00e8 praticamente tutto pronto per essere visualizzato sul nostro simulatore. Dobbiamo solo ricordarci di modificare un metodo di <em>MapViewController <\/em>in modo che, quando premiamo sul disclosure button utilizziamo il view controller appena creato:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {\r\n    InfoViewController *nextViewController = [[[InfoViewController alloc] initWithUserLocation:mapView.userLocation.location annotation:view.annotation] autorelease];\r\n    [self.navigationController pushViewController:nextViewController animated:YES];\r\n}\r\n<\/pre>\n<p>Questo il risultato sul simulatore&#8230;<\/p>\n<p><center><\/p>\n<table>\n<tr>\n<td>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/05\/MK02_3.png\" alt=\"\" width=\"213\" height=\"320\" \/>\n<\/td>\n<td>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignleft\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/05\/MK02_11.png\" alt=\"\" width=\"213\" height=\"320\" \/>\n<\/td>\n<\/tr>\n<\/table>\n<p><\/center><\/p>\n<p>&#8230; e sull&#8217;iPod.<\/p>\n<p><center><\/p>\n<table>\n<tr>\n<td>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/05\/MK02_5.png\" alt=\"\" width=\"213\" height=\"320\" \/>\n<\/td>\n<td>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignleft\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/05\/MK02_4.png\" alt=\"\" width=\"213\" height=\"320\" \/>\n<\/td>\n<\/tr>\n<\/table>\n<p><\/center><\/p>\n<p>Come l&#8217;altra volta trovate il codice completo su <a href=\"http:\/\/code.google.com\/p\/devapptutorials\/downloads\/list\" target=\"_blank\">Google code<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Con molto pi\u00f9 ritardo di quello che avevo previsto, ecco la seconda parte del tutorial riguardante il&#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,193,194,192,155,154,191,215,1],"class_list":["post-3133","post","type-post","status-publish","format-standard","hentry","category-tutorial-pratici","tag-annotation","tag-calcolo","tag-distanza","tag-geocoding","tag-kit","tag-map","tag-mapkit","tag-mappe","tag-tutorial-pratici"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3133","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=3133"}],"version-history":[{"count":67,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3133\/revisions"}],"predecessor-version":[{"id":3338,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3133\/revisions\/3338"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=3133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=3133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=3133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}