自定义注释苹果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<MKMapViewDelegate>' 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的主要内容,如果未能解决你的问题,请参考以下文章