向MKMapview添加自定义注释 [英] Adding a custom annotation to a MKMapview
问题描述
我正在尝试将注释添加到MKMapView
I am trying to add annotations to a MKMapView
我创建了一个符合MKAnnotation
协议
#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
我创建了一个类CustomMapAnnotationView
,它是MKAnnotationView
的子类
I have created a class CustomMapAnnotationView
which is a subclass of 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
和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;
}
这在地图上不显示任何内容.我该如何解决?
This does not show anything on the map. How do I fix this ?
推荐答案
在viewForAnnotation
中,CustomMapAnnotationView
从未实际分配+初始化(dequeueReusableAnnotationViewWithIdentifier
不会执行此操作).
In viewForAnnotation
, CustomMapAnnotationView
is never actually alloc+inited (the dequeueReusableAnnotationViewWithIdentifier
does not do this).
如果甚至调用了viewForAnnotation
,它必须返回nil
,这意味着地图视图必须在某个地方放置了一个红色的针(如果未调用委托方法,则地图视图将再次默认到一个红色别针).记录要添加注释的坐标,然后在其中查看.
If viewForAnnotation
is even getting called, it must be returning nil
which means the map view must be putting a red pin somewhere (and if the delegate method isn't getting called, then again the map view will default to a red pin). Log the coordinates where the annotation is being added and look there.
更正的viewForAnnotation
可能看起来像这样:
A corrected viewForAnnotation
might look like this:
-(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
后立即检索位置.不能保证每次都能正常工作,即使它正常"工作,您也很可能会获得旧的缓存位置.如果它不起作用,则注释将以0,0(大西洋)结尾,否则应用将因坐标无效而崩溃.最好在didUpdateLocations
委托方法中读取位置.在viewWillAppear
中,调用startUpdatingLocation
,然后在didUpdateLocations
中,如果该位置的准确性和年龄适合您,请调用stopUpdatingLocation
,然后使用该位置(创建并添加注释等). - 在
CustomMapAnnotationView
中,创建并添加了annotationImage
对象,但从未设置其image
属性.实际上,annotationImage
从未真正用于任何用途. - 整个
CustomMapAnnotationView
类对于您的目的都是不必要的.在viewForAnnotation
中,代码在CustomMapAnnotationView
上设置了image
属性(而不是使用annotationImage
).此image
属性是从MKAnnotationView
继承的.内置的基本MKAnnotationView
类是您执行工作所需的全部.它已经具有image
属性,它会自动为您显示该属性(您无需创建自己的UIImageView
).
- In
viewWillAppear
, code is retrieving the location immediately after callingstartUpdatingLocation
. This is not guaranteed to work every time and even if it does "work", you will most likely be getting an old, cached location. When it doesn't work, the annotation will either end up at 0,0 (Atlantic Ocean) or app will crash due to invalid coordinates. It's much better to read the location in thedidUpdateLocations
delegate method. InviewWillAppear
, callstartUpdatingLocation
and then indidUpdateLocations
, if the accuracy and age of the location is adequate for you, callstopUpdatingLocation
and then use the location (create and add the annotation, etc). - In
CustomMapAnnotationView
,annotationImage
object is created and added but itsimage
property is never set. TheannotationImage
is actually never really used for anything. - The whole
CustomMapAnnotationView
class is unnecessary for your purpose . InviewForAnnotation
, code is setting theimage
property on theCustomMapAnnotationView
(instead of usingannotationImage
). Thisimage
property is inherited fromMKAnnotationView
. The built-in, basicMKAnnotationView
class is all you need for what you're doing. It already has animage
property and it automatically displays it for you (you don't need to create your ownUIImageView
).
这篇关于向MKMapview添加自定义注释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!