MapView avec search locale

J'ai une question à propos de faire une search locale dans les maps Apple que j'ai déjà implémenté dans mon application. L'application devrait montrer à l'user où sont les «supermarchés» autour de lui. Ma mapView montre également l'location actuel de l'user, mais je ne sais pas vraiment comment je devrais le faire avec les résultats des marchés. Peut-être que Apple fournit une solution / un conseil pour cela. Merci d'avance.

Les résultats (supermarchés) doivent être affichés comme sur cette image

Les résultats (supermarchés) doivent être affichés comme sur cette image.

MISE À JOUR: La fonction fonctionne parfaitement, mais est-il également possible de rendre ces broches cliquables pour afficher une fiche d'information sur cet location comme dans les images ci-dessous?

entrez la description de l'image icientrez la description de l'image ici

MISE À JOUR 2: Je suis tellement fasciné par cette implémentation de carte, donc je me request s'il est aussi possible d'get des infos sur votre location actuel (comme dans la capture d'écran ci-dessous). entrez la description de l'image ici

Dans iOS 6.1 et MKLocalSearch ultérieures, vous pouvez utiliser MKLocalSearch , en ajoutant des annotations pour chacun des objects MKMapItem vous trouvez.

 MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init]; request.naturalLanguageQuery = @"supermarket"; request.region = mapView.region; MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request]; [search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) { for (MKMapItem *item in response.mapItems) { MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init]; annotation.coordinate = item.placemark.coordinate; annotation.title = item.name; annotation.subtitle = item.placemark.title; [mapView addAnnotation:annotation]; } }]; 

Si vous voulez les accessoires droit et gauche sur vos légendes, vous devez implémenter un viewForAnnotation qui ajoute ces accessoires (et bien sûr, pour que cela fonctionne, vous devez définir votre controller comme delegate pour votre MKMapView ):

 typedef enum : NSInteger { kCallOutAccessoryRight = 1, kCallOutAccessoryLeft } CallOutAccessoryType; - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { if ([annotation isKindOfClass:[MKUserLocation class]]) return nil; static NSSsortingng *identifier = @"customAnnotationView"; MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier]; if (annotationView == nil) { annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier]; annotationView.canShowCallout = YES; annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; annotationView.rightCalloutAccessoryView.tag = kCallOutAccessoryRight; annotationView.leftCalloutAccessoryView = ...; // whatever you want for the left button annotationView.leftCalloutAccessoryView.tag = kCallOutAccessoryLeft; } else { annotationView.annotation = annotation; } return annotationView; } 

Et, vous voulez probablement répondre à l'user en tapant sur ces appels:

 - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { if (control.tag == kCallOutAccessoryRight) { NSLog(@"Present info sheet for %@ here", [view.annotation title]); } else if (control.tag == kCallOutAccessoryLeft) { NSLog(@"Do whatever you want if left accessory tapped"); } } 

Vous avez demandé comment présenter les directions de l'user. Oui, vous pouvez le faire en passant un MKMapItem à openMapsWithItems . Mais cela présume que vous enregistrez le MKMapItem de la search locale. Pour ce faire, vous créez une annotation personnalisée. Par exemple:

 // MapItemAnnotation.h #import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface MapItemAnnotation : NSObject <MKAnnotation> @property (nonatomic, strong, readonly) MKMapItem *item; - (id)initWithMapItem:(MKMapItem *)item; - (NSSsortingng *)title; - (NSSsortingng *)subtitle; - (CLLocationCoordinate2D)coordinate; @end 

Et

 // MapItemAnnotation.m #import "MapItemAnnotation.h" @implementation MapItemAnnotation - (id)initWithMapItem:(MKMapItem *)item { self = [super init]; if (self) { _item = item; } return self; } - (NSSsortingng *)title { return _item.name; } - (NSSsortingng *)subtitle { return _item.placemark.title; } - (CLLocationCoordinate2D)coordinate { return _item.placemark.coordinate; } @end 

Après avoir fait cela, votre ajout de l'annotation à vos maps est simplifié un peu:

 [search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) { for (MKMapItem *item in response.mapItems) { MapItemAnnotation *annotation = [[MapItemAnnotation alloc] initWithMapItem:item]; [mapView addAnnotation:annotation]; } }]; 

Mais, maintenant, votre accessoire de légende gauche peut facilement initier des directions dans Apple Maps:

 - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { if (control.tag == kCallOutAccessoryRight) { NSLog(@"Present info sheet for %@ here", [view.annotation title]); } else if (control.tag == kCallOutAccessoryLeft) { // request directions from Apple Maps MapItemAnnotation *annotation = view.annotation; NSAssert([annotation isKindOfClass:[MapItemAnnotation class]], @"Annotation should be MapItemAnnotation: %@", annotation); [annotation.item openInMapsWithLaunchOptions:@{MKLaunchOptionsMapCenterKey : [NSValue valueWithMKCoordinate:mapView.region.center], MKLaunchOptionsMapSpanKey : [NSValue valueWithMKCoordinateSpan:mapView.region.span], MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving}]; } } 

En ce qui concerne la mise à jour de la description de l'location de l'user, vous pouvez définir une méthode didUpdateUserLocation (la vue de la carte appelle cette méthode MKMapViewDelegate chaque fois que l'location de l'user change). Il semble que vous souhaitiez mettre à jour les sous-titres pour l'location de l'user:

 - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation { [self updateSubtitleForUserLocation:userLocation]; } 

Cela appelle cette méthode qui ferait le géoencoding inverse et mettrait à jour le sous-titre en conséquence:

 - (void)updateSubtitleForUserLocation:(MKUserLocation *)userLocation { if ([self.geocoder isGeocoding]) [self.geocoder cancelGeocode]; [self.geocoder reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray *placemarks, NSError *error) { MKPlacemark *placemark = placemarks[0]; userLocation.subtitle = placemark.name; }]; } 

De toute évidence, vous avez besoin d'une propriété de class:

 @property (nonatomic, strong) CLGeocoder *geocoder; 

Et vous devez instancier cela, par exemple viewDidLoad pourrait:

 self.geocoder = [[CLGeocoder alloc] init]; 

Je pourrais affiner cela un peu pour ne faire un géoencoding inverse que si l'location de l'user a changé de plus de x mètres (vous ne voulez pas faire trop de requêtes de géoencoding inverse, vous allez tuer la batterie de l'user) l'idée.