自定义注释苹果mapkit

Posted

技术标签:

【中文标题】自定义注释苹果mapkit【英文标题】:custom annotation apple mapkit 【发布时间】:2013-12-08 03:57:15 【问题描述】:

我正在尝试分配两个自定义注释,一个名为“arsenal.png”,一个名为“chelsea.png”

使用苹果 mapkit 框架,xcode 7。

需要代码帮助来实现自定义标记。

这是我的实现文件:

// TrucksViewController.m

#import "TrucksViewController.h"
#import "Annotation.h"

@interface TrucksViewController ()

@end

//Wimbledon Coordinates
#define WIMB_LATITUDE 51.434783;
#define WIMB_LONGITUDE -0.213428;

//Stadium Coordinates
#define ARSENAL_LATITUDE 51.556899;
#define ARSENAL_LONGITUDE -0.106483;

#define CHELSEA_LATITUDE 51.481314;
#define CHELSEA_LONGITUDE -0.190129;

//Span
#define THE_SPAN 0.20f;

@implementation TrucksViewController
@synthesize myMapView;

#pragma mark -
#pragma mark Initialisation

- (id)initWithCoder:(NSCoder *)aDecoder 
self = [super initWithCoder:aDecoder];
if (self) 

    self.title = @"Trucks";

    [[UIApplication sharedApplication] setStatusBarHidden:NO     withAnimation:UIStatusBarAnimationNone];

return self;


#pragma mark -
#pragma mark UIViewController Delegates

- (void)didReceiveMemoryWarning 
[super didReceiveMemoryWarning];


- (void)viewDidUnload 
[super viewDidUnload];


-(void)viewWillAppear:(BOOL)animated 
[super viewWillAppear:animated];

// Update support ios 7
if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) 
    self.edgesForExtendedLayout = UIRectEdgeNone;
    self.navigationController.navigationBar.translucent = NO;



-(void)viewWillDisappear:(BOOL)animated 
[super viewWillDisappear:animated];

// Revert to default settings
if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) 
    self.edgesForExtendedLayout = UIRectEdgeAll;



- (void)viewDidLoad 

[super viewDidLoad];

//Create Region
MKCoordinateRegion myRegion;

//Center
CLLocationCoordinate2D center;
center.latitude = ARSENAL_LATITUDE;
center.longitude = ARSENAL_LONGITUDE;

//Span
MKCoordinateSpan span;
span.latitudeDelta = THE_SPAN;
span.longitudeDelta = THE_SPAN;

//Region
myRegion.center = center;
myRegion.span = span;

//Set our mapview
[myMapView setRegion:myRegion animated:YES];

//Annotation
NSMutableArray * locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
Annotation * myAnn;

//Arsenal annotation
myAnn = [[Annotation alloc] init];
location.latitude = ARSENAL_LATITUDE;
location.longitude = ARSENAL_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = @"Arsenal FC";
myAnn.subtitle = @"The Gunners";
[locations addObject:myAnn];

//Chelsea annotation
myAnn = [[Annotation alloc] init];
location.latitude = CHELSEA_LATITUDE;
location.longitude = CHELSEA_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = @"Chelsea FC";
myAnn.subtitle = @"The Blue Lions";
[locations addObject:myAnn];

[self.myMapView addAnnotations:locations];



@end

新增内容于 2013 年 12 月 11 日东部时间 18:31 发布

更新了 Annotations.h 文件

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

@interface Annotation : NSObject <MKAnnotation>

@property(nonatomic, assign) CLLocationCoordinate2D coordinate;
@property(nonatomic, copy) NSString * title;
@property(nonatomic, copy) NSString * subtitle;
@property(nonatomic, copy) NSString * imageName;

@end

更新了 Annotations.m 文件

#import "Annotation.h"

@implementation Annotation
@synthesize coordinate, title, subtitle, imageName;

@end

更新 TrucksViewController.h

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

@interface TrucksViewController : UIViewController 


@property (weak, nonatomic) IBOutlet MKMapView *myMapView;

@end

更新 TrucksViewController.m

(代码片段)

//Arsenal annotation
myAnn = [[Annotation alloc] init];
location.latitude = ARSENAL_LATITUDE;
location.longitude = ARSENAL_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = @"Arsenal FC";
myAnn.subtitle = @"The Gunners";
myAnn.imageName = @"arsenal";
[locations addObject:myAnn];

//Chelsea annotation
myAnn = [[Annotation alloc] init];
location.latitude = CHELSEA_LATITUDE;
location.longitude = CHELSEA_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = @"Chelsea FC";
myAnn.subtitle = @"The Blue Lions";
myAnn.imageName = @"chelsea";
[locations addObject:myAnn];

[self.myMapView addAnnotations:locations];



- (void)didReceiveMemoryWarning

[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.


@end

这是我更新的 TrucksViewController.m 文件: 2013 年 12 月 11 日东部时间 20:07

// TrucksViewController.m

#import "TrucksViewController.h"
#import "Annotation.h"

@interface TrucksViewController ()


@end

//Wimbledon Coordinates
#define WIMB_LATITUDE 51.434783;
#define WIMB_LONGITUDE -0.213428;

//Stadium Coordinates
#define ARSENAL_LATITUDE 51.556899;
#define ARSENAL_LONGITUDE -0.106483;

#define CHELSEA_LATITUDE 51.481314;
#define CHELSEA_LONGITUDE -0.190129;

//Span
#define THE_SPAN 0.20f;

@implementation TrucksViewController
@synthesize myMapView;

//insert code per Anna

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:    (id<MKAnnotation>)annotation

if ([annotation isKindOfClass:[Annotation class]])

    static NSString *reuseId = @"ann";
    MKAnnotationView *av = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
    if (av == nil)
    
        av = [[MKAnnotationView alloc] initWithAnnotation:annotation     reuseIdentifier:reuseId];
    
    else
    
        av.annotation = annotation;
    

    Annotation *ann = (Annotation *)annotation;
    av.image = [UIImage imageNamed:ann.imageName];

    return av;


//return nil (default view) if annotation is not our custom type
return nil;


//end new code per Anna

#pragma mark -
#pragma mark Initialisation

- (id)initWithCoder:(NSCoder *)aDecoder 
self = [super initWithCoder:aDecoder];
if (self) 
    // Set the title for this view controller
    // Note: In future we will copy over the title from any created     UINavigationBar objects
    self.title = @"Trucks";

    [[UIApplication sharedApplication] setStatusBarHidden:NO         withAnimation:UIStatusBarAnimationNone];

return self;


#pragma mark -
#pragma mark UIViewController Delegates

- (void)viewDidUnload 
[super viewDidUnload];


-(void)viewWillAppear:(BOOL)animated 
[super viewWillAppear:animated];

// Update support iOS 7
if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) 
    self.edgesForExtendedLayout = UIRectEdgeNone;
    self.navigationController.navigationBar.translucent = NO;



-(void)viewWillDisappear:(BOOL)animated 
[super viewWillDisappear:animated];

// Revert to default settings
if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) 
    self.edgesForExtendedLayout = UIRectEdgeAll;



- (void)viewDidLoad

[super viewDidLoad];

//Create Region
MKCoordinateRegion myRegion;

//Center
CLLocationCoordinate2D center;
center.latitude = ARSENAL_LATITUDE;
center.longitude = ARSENAL_LONGITUDE;

//Span
MKCoordinateSpan span;
span.latitudeDelta = THE_SPAN;
span.longitudeDelta = THE_SPAN;

//Region
myRegion.center = center;
myRegion.span = span;

//Set our mapview
[myMapView setRegion:myRegion animated:YES];

//Annotation
NSMutableArray * locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
Annotation * myAnn;

//Arsenal annotation
myAnn = [[Annotation alloc] init];
location.latitude = ARSENAL_LATITUDE;
location.longitude = ARSENAL_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = @"Arsenal FC";
myAnn.subtitle = @"The Gunners";
myAnn.imageName = @"arsenal.png";
[locations addObject:myAnn];

//Chelsea annotation
myAnn = [[Annotation alloc] init];
location.latitude = CHELSEA_LATITUDE;
location.longitude = CHELSEA_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = @"Chelsea FC";
myAnn.subtitle = @"The Blue Lions";
myAnn.imageName = @"chelsea.png";
[locations addObject:myAnn];

[self.myMapView addAnnotations:locations];



- (void)didReceiveMemoryWarning
   
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    

@end

【问题讨论】:

【参考方案1】:

您确实需要实现 viewForAnnotation 委托方法来为您的注释显示图像,而不是标准的红色图钉。

在该委托方法中,您需要创建并返回一个 MKAnnotationView 并将其 image 属性设置为您想要用于注释的图像。

您将获得对地图视图请求视图的注释的引用,并使用注释的属性,相应地设置图像。

可以将其基于注释的 title 值,但我建议改用以下方法:

    NSString 类型的imageName 属性添加到您的Annotation 类。在调用 addAnnotation 之前,将此属性设置为要用于注释的图像名称。例如:

    myAnn.title = @"Arsenal FC";
    myAnn.subtitle = @"The Gunners";
    myAnn.imageName = @"arsenal";
    [locations addObject:myAnn];
    

    viewForAnnotation委托方法中,检查注解是否为Annotation类型,然后使用其imageName属性设置注解视图的image属性:

    -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
    
        if ([annotation isKindOfClass:[Annotation class]])
        
            static NSString *reuseId = @"ann";
            MKAnnotationView *av = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
            if (av == nil)
            
                av = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
            
            else
            
                av.annotation = annotation;
            
    
            Annotation *ann = (Annotation *)annotation;
            av.image = [UIImage imageNamed:ann.imageName];
    
            return av;
        
    
        //return nil (default view) if annotation is not our custom type
        return nil;
    
    

另外,不要忘记设置地图视图的delegate 属性,否则委托方法将不会被调用。在 Interface Builder 中,将 delegate 出口连接到视图控制器。

【讨论】:

我在 TrucksViewController.m 中合并了上面的第 1 步,并更新了 Annotation.m 和 .h 以包含对 imageName 的引用。不确定如何实施第 2 步。 对于第 2 步,将答案中给出的 viewForAnnotation 方法添加到 TrucksViewController.m 文件中。确保地图视图的委托属性已设置(或插座已连接)。当然还要确保图像文件 arsenal.png、chelsea.png 等包含在您的项目中。 我在上面的原始帖子中包含了修改后的 TrucksViewController.m。 TrucksViewController.h 有一个出口,图像在项目中。我没有显示任何错误(是的!),但在 Simulator/Run 中显示了点,但带有默认的红色引脚(不是自定义图像)。 在 Interface Builder 中,右键单击地图视图。将委托出口连接到视图控制器。或者,在 viewDidLoad 中,在“super viewDidLoad”行之后添加这一行:self.myMapView.delegate = self; 成功运行(!)。没有错误,但有这个(黄色)警报/警告:Assigning to 'id&lt;MKMapViewDelegate&gt;' from incompatible type 'TrucksViewController *const __strong'【参考方案2】:

您可以使用 viewForAnnotation 委托方法来创建自定义注释。

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation

请参阅以下教程

http://www.codigator.com/tutorials/advanced-mapkit-tutorial-for-ios-custom-callout/

http://ios-funda.blogspot.in/2012/08/custom-annotations-example.html

编辑

您需要在viewDidLoad

中设置委托
self.myMapView.delegate = self

现在在 .h

@interface TrucksViewController : UIViewController<MKMapViewDelegate>

然后实现委托方法

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation  

    if ([annotation isKindOfClass:[MKUserLocation class]]) 
        return nil;
    

    static NSString *defaultPinId = @"Pin";
    CustomAnnotation *pinView = (CustomAnnotation *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinId];


    if (pinView == nil) 

        pinView = [[CustomAnnotation alloc]initWithAnnotation:annotation reuseIdentifier:defaultPinId];
        //pinView.pinColor = MKPinAnnotationColorRed;
        //pinView.animatesDrop = YES;
        pinView.canShowCallout = YES;
        //NSLog(@"%f",[annotation coordinate].latitude);

    
    else    
        pinView.annotation = annotation;
    


    UIButton *btn = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    btn.frame = CGRectMake(275, 27, 30, 30);

    //Adding a navigation inside a callout view
    btn.tag = [sid intValue];
    //NSLog(@"%i",btn.tag);
    [btn addTarget:self action:@selector(YOUR_SELECTOR) forControlEvents:UIControlEventTouchUpInside];
    pinView.rightCalloutAccessoryView = btn;

    return pinView;


CustomAnnotation.m中添加以下方法

-(id)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier    

    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
    if (self != nil) 
        CGRect frame = self.frame;
        frame.size = CGSizeMake(46.0, 49.0);
        self.frame = frame;
        self.backgroundColor = [UIColor clearColor];
        self.centerOffset = CGPointMake(-5, -5);
    
    return self;



// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect

    // Drawing code
    [[UIImage imageNamed:@"locatorico"] drawInRect:rect];


【讨论】:

我很抱歉。我花了几天时间浏览教程、视频、博客等(头部游泳)。不知道如何实现上面建议的代码。我在哪里插入上面的代码,以及如何将不同的(不同的).png 与每个位置相关联?谢谢! 为什么要用drawRect来显示图片?为什么不直接设置注释视图的image 属性?您实际上并不需要自定义注释视图类来显示注释图像。 @Anna 您可以简单地使用注释视图的图像属性。但是如果需要复杂的自定义或者需要添加任何额外的功能,那么这个自定义注解视图类会更有帮助 尽管您的情况可能需要进行此类自定义,但我认为它们不必要地使 OP 问题的简单性复杂化和混淆。 @Anna 是的。但我认为这种做法总是好的

以上是关于自定义注释苹果mapkit的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能让 mapkit 显示自定义注释图钉图像?

iPhone Mapkit 将自定义图像和引脚添加到注释中

MapKit 自定义注释被添加到地图,但在地图上不可见

IOS:将图像添加到自定义 MKAnnotationview

地图注释显示不正确的自定义图钉图像

MapKit 中的自定义地图样式