有关MapView的显示和定位在上一节已经说明,这一节说明如何在地图上放置大头针,以及设置点击大头针的视图。
【系统默认大头针】
mapView上放置大头针的方法是调用其addAnnotation:方法,需要注意的是,传入的是模型而不是大头针视图。
- (void)addAnnotation:(id )annotation;
通过这个方法,我们可以清楚的看到,annotation模型需要遵循MKAnnotation协议,我们打开这个协议,可以看到如下的内容:
@protocol MKAnnotation
// Center latitude and longitude of the annotation view.
// The implementation of this property must be KVO compliant.
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@optional
// Title and subtitle for use by selection UI.
@property (nonatomic, readonly, copy) NSString *title;
@property (nonatomic, readonly, copy) NSString *subtitle;
// Called as a result of dragging an annotation view.
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate NS_AVAILABLE(10_9, 4_0);
@end
因此我们应当定义一个模型,按照协议定义这些属性,其中coordinate是必须定义的,因为大头针必须有位置。
模型类遵循MKAnnocation协议,命名为MyAnnotation,如下:
#import
#import
@interface MyAnnotation : NSObject
/**
* 大头针的位置
*/
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
/**
* 大头针标题
*/
@property (nonatomic, copy) NSString *title;
/**
* 大头针的子标题
*/
@property (nonatomic, copy) NSString *subtitle;
@end
#import "MyAnnotation.h"
@implementation MyAnnotation
@end
然后就可以通过定义模型,调用addAnnotation:方法添加一枚大头针,例如我们通过Button,随机添加一枚大头针:
- (IBAction)addPin:(id)sender {
MyAnnotation *anno = [[MyAnnotation alloc] init];
anno.title = @"title";
anno.subtitle = @"subtitle";
CLLocationDegrees latitude = 36.821119 + arc4random_uniform(20);
CLLocationDegrees lOngtitude= 116.750112 + arc4random_uniform(20);
anno.coordinate = CLLocationCoordinate2DMake(latitude, longtitude);
[self.mapView addAnnotation:anno];
}
其中的title和subtitle是点击大头针时显示的气泡上的标题和副标题。
大头针的显示原理和tableView显示cell是类似的,一旦调用addAnnotation:方法,就会调用mapView:viewForAnnotationView:方法,这个方法中应当从缓存池取出一个大头针视图,或者如果缓存池中没有新建一个大头针视图,然后返回。
与tableView的区别是,如果直接返回nil,则会按照系统的样式返回大头针。
需要注意的是,如果不返回nil,要对不同类型的大头针进行处理,不要忘了用户的位置指示圆点也属于一种大头针,如果只是单单的设置大头针,连用户位置也会是一颗针而不是圆点。
判断方法很简单,因为用户位置大头针由系统创建,因此传入的模型肯定不是我们自己的模型MyAnnotation,只要判断传入的模型是不是这个类,如果不是,则返回nil,代表按照系统默认样式,创建圆点。
要创建大头针,使用的是MKPinAnnotationView,如果使用MKAnnotationView,是不带图片的,无法直接显示。
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{
static NSString *ID = @"anno";
// 如果返回nil,系统会按照默认方式显示,如果自定义,是无法直接显示的,并且点击大头针之后不会显示标题,需要自己手动设置显示
// 如果想要直接显示,应该调用MKPinAnnotationView
MKPinAnnotationView *annoView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID];
if (annoView == nil) {
annoView = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID];
// 大头针属性
annoView.animatesDrop = YES; // 设置大头针坠落的动画
annoView.canShowCallout = YES; // 设置点击大头针是否显示气泡
annoView.calloutOffset = CGPointMake(0, 0); // 设置大头针气泡的偏移
// 设置大头针气泡的左右视图、可以为任意UIView
annoView.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
annoView.rightCalloutAccessoryView = [[UISwitch alloc] init];
[annoView setPinColor:MKPinAnnotationColorPurple]; // 设置大头针颜色
}
// 设置大头针的图片,如果是直接创建MKPin,则无效。
//annoView.image = [UIImage imageNamed:@"pin"];
annoView.annotation = annotation;
// 如果是用户位置,应当显示默认的圆点而不是大头针,因此应当判断是否是MyAnnotation
if(![annoView.annotation isKindOfClass:[MyAnnotation class]]){
return nil;
}
return annoView;
}
【自定义大头针】
自定义大头针需要使用MKAnnotationView,自己指定image,没有坠落动画,其他没有区别。
(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{
static NSString *ID = @"anno";
// 如果返回nil,系统会按照默认方式显示,如果自定义,是无法直接显示的,并且点击大头针之后不会显示标题,需要自己手动设置显示
// 如果想要直接显示,应该调用MKPinAnnotationView
MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID];
if (annoView == nil) {
annoView = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID];
// 大头针属性
//annoView.animatesDrop = YES; // MKPinAnnotaionView才有效,设置大头针坠落的动画
annoView.canShowCallout = YES; // 设置点击大头针是否显示气泡
annoView.calloutOffset = CGPointMake(0, 0); // 设置大头针气泡的偏移
// 设置大头针气泡的左右视图、可以为任意UIView
annoView.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
annoView.rightCalloutAccessoryView = [[UISwitch alloc] init];
//[annoView setPinColor:MKPinAnnotationColorPurple]; // MKPinAnnotaionView才有效,设置大头针的颜色
}
// 设置大头针的图片
annoView.image = [UIImage imageNamed:@"pin"];
annoView.annotation = annotation;
// 如果是用户位置,应当显示默认的圆点而不是大头针,因此应当判断是否是MyAnnotation
if(![annoView.annotation isKindOfClass:[MyAnnotation class]]){
return nil;
}
return annoView;
}
【MVC封装annotationView的注意点】
annotation要传入模型,在重写的set方法里,注意调用父类的set方法,先设置公共属性,再设置自己所特有的。
有一个细节,默认set方法的传入模型是id类型,在使用时还需要强转类型,为了方便,我们直接把类型改为MyAnnotation,因为OC在调用方法时发送的消息只包括方法名和冒号、描述,因此类型不属于方法名的一部分,可以修改。
- (void)setAnnotation:(MyAnnotation *)annotation{
[super setAnnotation:annotation];
// 设置特有的属性,例如图片、左右视图等。
}