向 MKMapview 添加自定义注释

Adding a custom annotation to a MKMapview

我正在尝试向 MKMapView

添加注释

我创建了一个符合 MKAnnotation 协议的 class CustomMapPin

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface CustomMapPin : NSObject <MKAnnotation> {

    CLLocationCoordinate2D coordinate;
    NSString *title;
    NSString *subtitle;
}

@property(nonatomic, assign) CLLocationCoordinate2D coordinate;
@property(nonatomic, copy) NSString *title;
@property(nonatomic, copy) NSString *subtitle;
@property(nonatomic, strong) NSString *type; // this is to differentiate between the different annotations on the map

@end

我创建了一个 class CustomMapAnnotationView,它是 MKAnnotationView

的子class

CustomMapAnnotationView.h

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface CustomMapAnnotationView : MKAnnotationView
@property (nonatomic, strong) UIImageView *annotationImage;
@end

CustomMapAnnotationView.m

#import "CustomMapAnnotationView.h"

@implementation CustomMapAnnotationView

-(id) initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];

    if (self) {
        self.frame = CGRectMake(0, 0, 28, 40);
        self.backgroundColor = [UIColor clearColor];

        self.annotationImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 28, 40)];
        self.annotationImage.contentMode = UIViewContentModeScaleAspectFit;
        [self addSubview:self.annotationImage];

    }
    return self;
}

@end

我正在 FindMechanicViewController 中添加自定义引脚,它是 CLLocationManagerDelegateMKMapViewDelegate

代码片段是:

-(void) viewWillAppear:(BOOL)animated {
    [self.locationManager startUpdatingLocation];
    self.currentLocation = [self.locationManager location];

    // Set the region of the map
    MKCoordinateSpan mapViewSpan = MKCoordinateSpanMake(0.01, 0.01);
    MKCoordinateRegion mapRegion = MKCoordinateRegionMake(self.currentLocation.coordinate, mapViewSpan);
    [self.mapView setRegion:mapRegion];

    // Add custom pin showing user location
    CustomMapPin *annotation = [[CustomMapPin alloc] init];
    annotation.title = @"Current Location";
    annotation.coordinate = self.currentLocation.coordinate;
    annotation.type = @"user location";
    [self.mapView addAnnotation:annotation];
}

和委托方法

-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    static NSString *reuseId = @"CustomMapPin";
    CustomMapAnnotationView *annotationView = (CustomMapAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];

    if ([annotation isKindOfClass:[CustomMapPin class]]) {
        CustomMapPin *customAnnotation = (CustomMapPin *)annotation;

       if ([customAnnotation.type isEqualToString:@"user location"]) {
           [annotationView setAnnotation:customAnnotation];
           [annotationView setImage:[UIImage imageNamed:@"pin_user"]];
           [annotationView setCanShowCallout:YES];
        }

    }
    return annotationView;
}

地图上没有显示任何内容。我该如何解决这个问题?

viewForAnnotation 中,CustomMapAnnotationView 实际上从未被分配+初始化(dequeueReusableAnnotationViewWithIdentifier 不会这样做)。

如果 viewForAnnotation 甚至被调用,它必须返回 nil 这意味着地图视图必须在某处放置一个红色图钉(如果委托方法没有被调用,那么地图视图将再次默认为红色图钉)。记录添加注释的坐标并查看那里。

更正后的 viewForAnnotation 可能如下所示:

-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    if ([annotation isKindOfClass:[CustomMapPin class]]) {
        static NSString *reuseId = @"CustomMapPin";

        CustomMapAnnotationView *annotationView = (CustomMapAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
        if (!annotationView) {
            annotationView = [[CustomMapAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
            [annotationView setCanShowCallout:YES];
        }

        CustomMapPin *customAnnotation = (CustomMapPin *)annotation;

        //view's annotation should be set regardless of "type"
        [annotationView setAnnotation:customAnnotation];

        if ([customAnnotation.type isEqualToString:@"user location"]) {
            [annotationView setImage:[UIImage imageNamed:@"pin_user"]];
        }
        else {
            //If it's not a "user location", then set image
            //to something else otherwise image will either be nil
            //or it will show some other annotation's image...
            [annotationView setImage:[UIImage imageNamed:@"pin_other"]];
        }

        return annotationView;
    }

    return nil;
}

代码的一些其他问题:

  1. viewWillAppear 中,代码在调用 startUpdatingLocation 后立即检索位置。这不能保证每次都有效,即使它 "work",您也很可能会得到一个旧的缓存位置。当它不起作用时,注释将以 0,0(大西洋)结束,或者应用程序将因无效坐标而崩溃。最好在 didUpdateLocations 委托方法中读取位置。在 viewWillAppear 中,调用 startUpdatingLocation,然后在 didUpdateLocations 中,如果位置的准确性和年龄对您来说足够,请调用 stopUpdatingLocation,然后使用该位置(创建并添加注释等)。
  2. CustomMapAnnotationView 中,创建并添加了 annotationImage 对象,但从未设置其 image 属性。 annotationImage 实际上从未真正用于任何用途。
  3. 整个 CustomMapAnnotationView class 对于您的目的来说是不必要的。在 viewForAnnotation 中,代码在 CustomMapAnnotationView 上设置 image 属性(而不是使用 annotationImage)。这个image属性是继承自MKAnnotationView。内置的基本 MKAnnotationView class 是您所需要的一切。它已经有一个 image 属性 并且它会自动为您显示它(您不需要创建自己的 UIImageView)。