1

我有一个关于在我已经在我的应用程序中实现的 Apple 地图中进行本地搜索的问题。该应用程序应该向用户显示他周围的“超市”在哪里。我的 mapView 还显示了用户的当前位置,但我真的不知道应该如何处理市场位置的结果。也许苹果为此提供了解决方案/建议。提前致谢。

结果(超市)应该显示在这张图片中

结果(超市)应显示在此图片中。

更新: 该功能完美运行,但是否也可以使这些引脚可点击以显示有关此位置的信息表,如下图所示?

在此处输入图像描述 在此处输入图像描述

更新 2: 我对这个地图实现非常着迷,所以我想知道是否也可以获取有关您当前位置的信息(如下面的屏幕截图所示)。 在此处输入图像描述

4

1 回答 1

2

在 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添加这些配件的 a (当然,要使其正常工作,您必须将控制器定义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");
    }
}

您问如何呈现用户方向。是的,您可以通过将其传递MKMapItemopenMapsWithItems. 但这假设您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

完成此操作后,将注释添加到地图会稍微简化一点:

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

但是,现在,您的左侧标注配件可以轻松地在 Apple 地图中启动路线:

- (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方法(即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米,我可能会稍微改进一下,只进行反向地理编码(你不想做太多的反向地理编码请求;你会耗尽用户的电池),但希望这能说明这个想法。

于 2013-07-16T17:59:50.467 回答