我有一个关于在Apple Maps中进行本地搜索的问题,而我已经在我的应用程序中实现了该搜索。
该应用程序应向用户显示他周围的“超市”在哪里。我的mapView还显示了用户的当前位置,但是我真的不知道如何使用市场位置的结果来执行此操作。也许Apple为此提供了解决方案/建议。
提前致谢。
结果( super 市场)应如图所示。
更新:
该功能运行良好,但是否也可以使这些引脚可单击以显示有关此位置的信息表,如下图所示?
更新2:
我对这个 map 实现非常着迷,所以我想知道是否还可以获取有关您当前位置的信息(如下面的屏幕截图所示)。
最佳答案
在iOS 6.1和更高版本中,您可以使用 MKLocalSearch
,为找到的每个 MKMapItem
对象添加注释。
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];
}
}];
如果要在标注上使用左右附件,则应实现添加这些附件的
viewForAnnotation
(当然,要使其正常工作,必须将控制器定义为delegate
的MKMapView
):typedef enum : NSInteger
{
kCallOutAccessoryRight = 1,
kCallOutAccessoryLeft
} CallOutAccessoryType;
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *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;
}
而且,您大概想响应用户点击这些标注的情况:
- (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");
}
}
您询问了如何显示用户指南。是的,您可以通过将
MKMapItem
传递给openMapsWithItems
来实现。但这假设您保存了本地搜索中的MKMapItem
。为此,您要创建一个自定义注释。例如:// MapItemAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface MapItemAnnotation : NSObject <MKAnnotation>
@property (nonatomic, strong, readonly) MKMapItem *item;
- (id)initWithMapItem:(MKMapItem *)item;
- (NSString *)title;
- (NSString *)subtitle;
- (CLLocationCoordinate2D)coordinate;
@end
和
// MapItemAnnotation.m
#import "MapItemAnnotation.h"
@implementation MapItemAnnotation
- (id)initWithMapItem:(MKMapItem *)item
{
self = [super init];
if (self) {
_item = item;
}
return self;
}
- (NSString *)title
{
return _item.name;
}
- (NSString *)subtitle
{
return _item.placemark.title;
}
- (CLLocationCoordinate2D)coordinate
{
return _item.placemark.coordinate;
}
@end
完成此操作后,将批注添加到 map 的过程得到了简化:
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
for (MKMapItem *item in response.mapItems)
{
MapItemAnnotation *annotation = [[MapItemAnnotation alloc] initWithMapItem:item];
[mapView addAnnotation:annotation];
}
}];
但是,现在,您的左侧标注附件可以轻松在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}];
}
}
关于更新用户位置描述,您可以定义
didUpdateUserLocation
方法(即,每次用户位置更改时, map 视图都会调用 MKMapViewDelegate
方法)。您似乎要更新用户位置的字幕:- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
[self updateSubtitleForUserLocation:userLocation];
}
这将调用此方法,该方法将执行反向地址解析并相应地更新字幕:
- (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;
}];
}
显然,您需要一个类属性:
@property (nonatomic, strong) CLGeocoder *geocoder;
并且您需要实例化它,例如
viewDidLoad
可以:self.geocoder = [[CLGeocoder alloc] init];
如果用户的位置变化超过x米(您不想进行过多的反向地理编码请求;您会杀死用户的电池),我可能会对此做一些改进以仅执行反向地理编码。这个想法。