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