具有本地搜索功能的MapView [英] MapView with local search

查看:74
本文介绍了具有本地搜索功能的MapView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对在我的应用程序中已经实现的Apple Maps中进行本地搜索存在疑问. 该应用程序应向用户显示他周围的超级市场"在哪里.我的mapView还显示了用户的当前位置,但是我真的不知道如何使用市场位置的结果来执行此操作.也许Apple为此提供了解决方案/建议. 预先感谢.

I've a question about doing a local search in Apple maps which I have already implemented into my app. The app should show the user where are "supermarkets" around him. My mapView also shows the user's current location but I don't really know how I should do this with the results of the market-locations. Maybe Apple provides a solution/advice for this. Thanks in advance.

结果(超级市场)应如下图所示.

The results (supermarkets) should be displayed as in this picture.

更新: 该功能可以正常工作,但是否可以使这些 pins 可单击以显示有关此位置的信息表,如下图所示?

UPDATE: The function works perfectly but is it also possible to make these pins clickable to show an info-sheet about this location as in the pictures below?

更新2: 我对这个地图实现非常着迷,所以我想知道是否还可以获取有关您当前位置的信息(如下面的屏幕截图所示).

UPDATE 2: I'm so fascinated from this map-implemention, so I wonder if it's also possible to get infos about your current location (as in the screenshot below).

推荐答案

在iOS 6.1和更高版本中,您可以使用

In iOS 6.1 and later, you can use MKLocalSearch, adding annotations for each of the MKMapItem objects you find.

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):

If you want the right and left accessories on your callouts, you should implement a viewForAnnotation that adds those accessories (and of course, for this to work, you have to define your controller to be the delegate for your 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;
}

而且,您大概想响应用户点击这些标注的情况:

And, you presumably want to respond to the user tapping on those callouts:

- (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.为此,您要创建一个自定义注释.例如:


You asked how to present the user directions. Yes, you can do that by passing it a MKMapItem to openMapsWithItems. But that presumes that you save the MKMapItem from the local search. To do this, you're creating a custom annotation. For example:

//  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

这样做,将注释添加到地图的过程得到了简化:

Having done that, your adding the annotation to your maps is simplified a bit:

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

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

But, now, your left callout accessory can easily initiate directions in 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}];
    }
}


关于更新用户位置描述,您可以定义


Regarding updating the user location description, you can define a didUpdateUserLocation method (i.e. the map view calls this MKMapViewDelegate method every time the user's location changes). It looks like you want to update the subtitle for the user's location:

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

将调用此方法,该方法将执行反向地址解析并相应地更新字幕:

That would call this method that would do the reverse geocode and update the subtitle accordingly:

- (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;
    }];
}

很显然,您需要一个类属性:

Clearly, you need a class property:

@property (nonatomic, strong) CLGeocoder *geocoder;

您需要实例化它,例如viewDidLoad可以:

And you need to instantiate that, e.g. viewDidLoad could:

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

如果用户的位置变化超过 x 米(我不想进行太多的反向地理编码请求,我可能会对此做一些改进,以仅进行反向地理编码)杀死用户的电池),但希望可以说明这一想法.

I might refine this a bit to only do a reverse geocode if the user's location has changed by more than x meters (you don't want to do too many reverse geocode requests; you'll kill the user's battery), but hopefully this illustrates the idea.

这篇关于具有本地搜索功能的MapView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆