地图与定位(三)自定义大头针视图

1. 自定义大头针视图

前文中,我们看到添加的大头针在地图上显示的形式都是一样的,采用系统默认的大头针样式。在一些应用中系统默认的大头针样式可能无法满足实际的需求,此时就需要修改大头针视图默认样式。事实上,MKMapView的代理方法- (MKAnnotationView )mapView:(MKMapView )mapView viewForAnnotation:(id )annotation;可以返回一个大头针视图,只要实现这个方法并在这个方法中定义一个大头针视图MKAnnotationView对象并设置相关属性就可以改变默认大头针的样式。当然如果代理方法返回nil则会使用默认大头针视图,需要根据情况设置,比如添加的大头针数据为用户当前位置(MKUserAnnotation)。

通过上面的代理方法自定义大头针视图需要注意代理方法的调用时机:每当有大头针显示到系统可视界面中时就会调用此方法返回一个大头针视图放到界面中,同时当前系统位置标注(也就是地图中蓝色的位置点)也是一个大头针,也会调用此方法,因此处理大头针视图时需要区别对待(通过大头针数据模型)。另外类似于UITableView的代理方法,此方法调用频繁,开发过程中需要重复利用MapKit的缓存池将大头针视图缓存起来重复利用。自定义大头针默认情况下不允许交互,如果交互需要设置属性显示大头针视图的标题以区分大头针视图。下面是MKAnnotationView的常用属性:

属性 说明
annotation 大头针模型信息,包括标题、子标题、地理位置。
image 大头针图片
canShowCallout 点击大头针是否显示标题、子标题内容等,注意如果在- (MKAnnotationView )mapView:(MKMapView )mapView viewForAnnotation:(id )annotation;方法中重新定义大头针默认情况是无法交互的需要设置为true。
calloutOffset 点击大头针时弹出详情信息视图的偏移量
selected 是否被选中状态
leftCalloutAccessoryView 弹出详情左侧视图
rightCalloutAccessoryView 弹出详情右侧视图

从上面的属性中,我们不难看出,当我们自定义大头针视图时,除了可以添加大头针的图片之外,我们还可以设置更多的大头针视图属性,比如弹出视图、偏移量等信息。

示例代码:
自定义大头针数据模型:
Annotation.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

添加大头针数据,并返回大头针视图

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#import "Annotation.h"

@interface ViewController ()<CLLocationManagerDelegate,MKMapViewDelegate>

@property (nonatomic, strong)CLLocationManager *locationManager;
@property (nonatomic, strong)MKMapView *mapView;

@end

@implementation ViewController

- (CLLocationManager *)locationManager {

    if (!_locationManager) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
    }
    return _locationManager;
}

- (MKMapView *)mapView {

    if (!_mapView) {
        _mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
        //设置地图样式
        _mapView.mapType = MKMapTypeStandard;
        //设置用于追踪模式
        _mapView.userTrackingMode = MKUserTrackingModeFollow;
        _mapView.delegate = self;
    }
    return _mapView;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addSubview:self.mapView];

    //1.判断手机定位服务是否打开
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"手机定位服务没有打开");
        return;
    }

    //2.iOS8.0以上的用户需要授权
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
        if ([[[UIDevice currentDevice]  systemVersion] floatValue] >= 8.0) {
            //调用此方法之前必须在plist文件中添加NSLocationWhenInUseUsageDescription --string-- 后面跟的文字就是提示信息
            [self.locationManager requestWhenInUseAuthorization];
        }
    }
}
// 添加大头针数据模型
- (void)addAnnotation {

    // 酒店大头针数据
    Annotation *anno1 = [[Annotation alloc] init];
    anno1.coordinate = CLLocationCoordinate2DMake(39.9, 116);
    anno1.title = @"xxx酒店";
    anno1.subtitle = @"周末8折,会员5折";
    anno1.imageName = @"category_3";
    [self.mapView addAnnotation:anno1];

    // 影院大头针
    Annotation *anno2 = [[Annotation alloc] init];
    anno2.coordinate = CLLocationCoordinate2DMake(40, 117);
    anno2.title = @"xxx影院";
    anno2.subtitle = @"《夏洛 特 烦恼》 正在热映,周末免费";
    anno2.imageName = @"category_5";
    [self.mapView addAnnotation:anno2];
}

#pragma mapViewDelegate
/**
 *  用户位置发生改变的时候调用这个方法
 *
 *  @param mapView      地图
 *  @param userLocation 地图上蓝色的那颗大头针数据(注意不是那个蓝色的视图)
 */
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    userLocation.title = @"北京市";
    userLocation.subtitle = @"中国首都";
    NSLog(@"%f , %f",userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude);

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        //设置地图显示的区域
        //获取中心点位置
        CLLocationCoordinate2D center = userLocation.location.coordinate;
        //显示跨度
        MKCoordinateSpan span = MKCoordinateSpanMake(4.193344, 3.069712);
        //region
        MKCoordinateRegion region = MKCoordinateRegionMake(center,  span);
        [mapView setRegion:region animated:YES];

        [self addAnnotation];// 添加大头针数据
    });
}

/**
 *  产生大头针视图调用的方法(自定义大头针时实现该代理方法)
 *
 *  @param mapView    地图
 *  @param annotation 大头针描述数据
 *
 *  @return 大头针视图
 */
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

    // 添加用户的大头针模型MKUserLocation时也会调用该代理方法,所以需要区别判断
    if ([annotation isKindOfClass:[Annotation class]]) {

        // 大头针视图的复用标识
        static NSString *identifier = @"annotation";

        // 从缓存池中取出可以循环利用的大头针视图
        MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];

        // 创建大头针视图
        if (annotationView == nil) {
            // 如果复用池中没有大头针视图,那么我们就创建并且设置描述数据和标识
            annotationView = [[MKAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:identifier];

            // 显示大头针的子标题和标题
            annotationView.canShowCallout = YES;
            // 设置大头针描述的偏移量
            annotationView.calloutOffset = CGPointMake(0, -10);

            // 设置大头针描述右边的控件
            //添加大头针右边控件
            UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoLight];
            [button addTarget:self action:@selector(buttonAction1:) forControlEvents:UIControlEventTouchUpInside];
            annotationView.rightCalloutAccessoryView = button;
            // 设置大头针描述左边的控件
            annotationView.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

        }
        // 传递数据模型
        annotationView.annotation = annotation;
        // 获取加载的大头针模型设置图片
        Annotation *anno = annotation;
        annotationView.image = [UIImage imageNamed:anno.imageName];

        return annotationView;// 返回nil,使用系统自带的大头针
    }

    return nil;// 返回nil,使用系统自带的大头针模型
}

- (void)buttonAction1:(UIButton *)btn
{
    UIViewController *detailVC = [[UIViewController alloc] init];
    detailVC.view.backgroundColor = [UIColor greenColor];
    detailVC.title = @"详情信息";
    [self.navigationController pushViewController:detailVC animated:YES];
}
@end

除了使用MKAnnotationView类来定制大头针视图外,在MapKit框架中除了MKAnnotationView之外还有一个MKPinAnnotationView,它是MKAnnotationView的子类,相比MKAnnotationView多了两个属性pinColor和animationDrop,分别用于设置大头针视图颜色和添加大头针动画。

示例代码:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    //判断annotation是不是Annotation,一定要判断否则报错  -[MKUserLocation icon]:
    if ([annotation isKindOfClass:[Annotation class]]) {

        //大头针复用标识
        static NSString *identifier = @"identifier";
        //从复用池中取出大头针视图:MKPinAnnotationView可以实现大头针视图从天而降的动画效果
        MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];

        if (annotationView == nil) {
            //如果复用池中没有大头针视图,那么我们就创建并且根据描述数据和标识
            //不能兼顾图片和动画,实现的话需要自己子类化
            annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
            //从天而降效果
            annotationView.animatesDrop = YES;
            //设置大头针背景颜色
            annotationView.backgroundColor = [UIColor greenColor];

            //显示大头针的主标题和副标题
            annotationView.canShowCallout = YES;
            //设置主标题和副标题移动距离
            annotationView.calloutOffset = CGPointMake(0, -30);
        }
        //传递模型数据  避免复用
        annotationView.annotation = annotation;

        // 获取加载的大头针模型 设置图片
        Annotation *bvAnnotation = annotation;
        annotationView.image = [UIImage imageNamed:bvAnnotation.imageName];

        return  annotationView;
    }
    return nil;
}

上面的代码中,我们发现添加大头针视图时有了一个从天而降的动画效果,但是,我们给大头针视图添加的大头针图片并没有显示,要想同时事项上面的两个功能,就需要我们对MKPinAnnotationView做子类化,并添加一个图片了。

示例代码:
自定义大头针视图:PinAnnotationView.h

#import "PinAnnotationView.h"
#import "Annotation.h"

@implementation PinAnnotationView

// 复写初始化方法
- (id)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {

    if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) {

        // 在大头针视图上添加一个UIImageView用来显示大头针图片
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(-10, 0, 38, 44)];
        imageView.tag = 1001;
        imageView.backgroundColor = [UIColor clearColor];
        imageView.userInteractionEnabled = YES;
        [self addSubview:imageView];

        // 判断加载的数据类型
        if ([annotation isKindOfClass:[Annotation class]]) {
            Annotation *anno = annotation;
            // 获取大头针图片名称
            NSString *imageName = anno.imageName;
            UIImage *image = [UIImage imageNamed:imageName];
            imageView.image = image;
        }
    }
    return self;
}

// 复用大头针视图时刷新图片数据,避免复用
- (void)setAnnotation:(id<MKAnnotation>)annotation {
    [super setAnnotation:annotation];

    UIImageView *imageView = (UIImageView *)[self viewWithTag:1001];
    // 判断加载的数据类型
    if ([annotation isKindOfClass:[Annotation class]]) {
        Annotation *anno = annotation;
        // 获取大头针图片名称
        NSString *imageName = anno.imageName;
        UIImage *image = [UIImage imageNamed:imageName];
        imageView.image = image;
    }
}

@end

添加自定义的大头针视图

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    //判断annotation是不是BVAnnotation,一定要判断否则报错  -[MKUserLocation icon]:
    if ([annotation isKindOfClass:[Annotation class]]) {

        //大头针复用标识
        static NSString *identifier = @"identifier";
        //从复用池中取出大头针视图 (实现从天而降的动画)
        PinAnnotationView *annotationView = (PinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        if (annotationView == nil) {
            //如果复用池中没有大头针视图,那么我们就创建并且根据描述数据和标识
            //不能兼顾图片和动画,实现的话需要自己子类化
            annotationView = [[PinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
            //从天而降效果
            annotationView.animatesDrop = YES;
            //设置大头针背景颜色
//            annotationView.backgroundColor = [UIColor greenColor];

            //显示大头针的主标题和副标题
            annotationView.canShowCallout = YES;
            //设置主标题和副标题移动距离
            annotationView.calloutOffset = CGPointMake(0, -30);
            //添加大头针右边控件
            UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoLight];
            [button addTarget:self action:@selector(buttonAction1:) forControlEvents:UIControlEventTouchUpInside];
            annotationView.rightCalloutAccessoryView = button;

        }

        //传递模型数据  避免复用
        annotationView.annotation = annotation;

        // 获取加载的大头针模型 设置图片
        Annotation *anno = annotation;
        annotationView.image = [UIImage imageNamed:anno.imageName];

        return annotationView;
    }
    return nil;
}

上面的代码有一个坑点,复用大头针视图时,为了避免大头针图片加载出错,我们去刷新了大头针视图的数据,并给大头针视图的image属性重新赋值,子类化是我们复写image的set方法却是无法显示图片的,这可能也是MKPinAnnotationView无法显示大头针图片的原因所在,所以看到我们改变大头针图片时是在annotation的方法中实现的。

2. 自定义大头针弹详情视图

通过上面的示例不难看出MKAnnotationView足够强大(何况还有MKPinAnnotationView),很多信息都可以进行设置,但是唯独不能修改大头针描述详情视图(仅仅支持详情中左右视图内容)。要实现这个需求目前开发中普遍采用的思路就是:

  • 点击一个大头针A时重新在A的坐标处添加另一个大头针B(注意此时将A对应的大头针视图canShowCallout设置为false)作为大头针详情模型,然后在- (MKAnnotationView )mapView:(MKMapView )mapView viewForAnnotation:(id )annotation;代理方法中判断大头针类型,如果是B则重写MKAnnotationView(可以自定义一个类C继承于MKAnnotationView),返回自定义大头针视图C。

  • 定义大头针视图C继承于MKAnnotationView(或者MKPinAnnotationView),在自定义大头针视图中添加自己的控件,完成自定义布局。

    下面不妨试着实现一下自定义大头针弹出视图的效果,在这个过程中需要注意几点:

  • 大头针A作为一个普通大头针,其中最好保存自定义大头针视图C所需要的模型以便根据不同的模型初始化视图。

  • 自定义大头针视图C的大头针模型B中最后保存自定义大头针视图C所需要的布局模型数据。
  • 只有点击非B类大头针时才新增自定义大头针,并且增加时要首先移除其他B类大头针避免重叠(一般建议放到取消大头针选择的代理方法中)。
  • 通常在自定义大头针视图C设置大头针模型时布局界面,此时需要注意新增大头针的位置,通常需要偏移一定的距离才能达到理想的效果。

示例代码:
自定义添加的大头针模型:Annotation.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,strong) UIImage *image;

// 大头针详情左侧图标
@property (nonatomic,strong) UIImage *icon;
// 大头针详情描述
@property (nonatomic,copy) NSString *detail;

@end

自定义弹出详情大头针模型:CalloutAnnotation.h

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

@interface CalloutAnnotation : NSObject<MKAnnotation>

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

// 左侧图标
@property (nonatomic,strong) UIImage *icon;
// 详情描述
@property (nonatomic,copy) NSString *detail;

@end

弹出详情大头针视图:KCCalloutAnnotatonView.h
import <MapKit/MapKit.h>

@interface CalloutAnnotationView : MKAnnotationView

+ (instancetype)annotationViewWithMapView:(MKMapView *)mapView;

@end
CalloutAnnotationView.m
#import "CalloutAnnotationView.h"
#import "CalloutAnnotation.h"

@implementation CalloutAnnotationView
{
    UIImageView *_iconImageView;
    UILabel *_titleLabel;
    UILabel *_subTitleLabel;
}
+ (instancetype)annotationViewWithMapView:(MKMapView *)mapView {

    static NSString *identifier = @"CalloutAnnotationView";
    // 从复用池里获取大头针视图
    CalloutAnnotationView *annoView = (CalloutAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
    if (annoView == nil) {
        //初始化大头针视图 ,大头针模型数据外部传递
        annoView = [[CalloutAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:identifier];
    }
    return annoView;
}

//外部传递大头针模型数据 annotation:BVAnnotation
- (void)setAnnotation:(id<MKAnnotation>)annotation {
    [super setAnnotation:annotation];

    //获取该视图传入大头针的模型数据
    CalloutAnnotation *anno = annotation;
    _iconImageView.image = anno.icon;
    _titleLabel.text = anno.title;
    _subTitleLabel.text = anno.subtitle;

}

// 大头针视图本质上讲就是一个UIView 初始化时还是会走该方法,所以可以在该方法中添加详情视图
- (id)initWithFrame:(CGRect)frame {

    if (self = [super initWithFrame:frame]) {

        self.frame = CGRectMake(0, 0, 150, 200);
        self.backgroundColor = [UIColor clearColor];
        [self creatSubView];
    }
    return self;
}

// 添加子视图时会调用次方法,我们在这里设置详情视图的弹出动画
- (void)didMoveToSuperview {
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
    anim.keyPath = @"transform.scale";
    anim.values = @[@0, @1.5, @1, @1.5, @1];
    anim.duration = 0.5;
    [self.layer addAnimation:anim forKey:nil];
}

- (void)creatSubView {

    UIView *detailView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 150, 70)];
    detailView.backgroundColor = [UIColor clearColor];
    [self addSubview:detailView];

    UIImageView *bgView = [[UIImageView alloc] initWithFrame:detailView.bounds];
    bgView.image = [[UIImage imageNamed:@"bg_map_cell"] stretchableImageWithLeftCapWidth:0 topCapHeight:9];
    [detailView addSubview:bgView];

    _iconImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 40, 40)];
    [self addSubview:_iconImageView];

    _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, 80, 25)];
    _titleLabel.textColor = [UIColor blueColor];
    _titleLabel.textAlignment = NSTextAlignmentLeft;
    _titleLabel.font = [UIFont systemFontOfSize:17];
    [self addSubview:_titleLabel];

    _subTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 25, 80, 25)];
    _subTitleLabel.textColor = [UIColor blueColor];
    _subTitleLabel.numberOfLines = 0;
    _subTitleLabel.textAlignment = NSTextAlignmentLeft;
    _subTitleLabel.font = [UIFont systemFontOfSize:12];
    [self addSubview:_subTitleLabel];
}
@end

主视图控制器:KCMainViewController.m

#import "ViewController.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "Annotation.h"
#import "AnnotationView.h"
#import "CalloutAnnotation.h"
#import "CalloutAnnotationView.h"

@interface ViewController ()<CLLocationManagerDelegate,MKMapViewDelegate>

@property (nonatomic, strong)MKMapView *mapView;
@property (nonatomic, strong)CLLocationManager *locationManager;

@end

@implementation ViewController

- (CLLocationManager *)locationManager {

    if (!_locationManager) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
    }
    return _locationManager;
}

- (MKMapView *)mapView {

    if (!_mapView) {
        _mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
        _mapView.delegate = self;
        //设置地图样式
        _mapView.mapType = MKMapTypeStandard;
        //设置用于追踪模式
        _mapView.userTrackingMode = MKUserTrackingModeFollow;
    }
    return _mapView;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addSubview:self.mapView];

    //1.判断手机定位服务是否打开
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"手机定位服务没有打开");
        return;
    }

    //2.iOS8.0以上的用户需要授权
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
        if ([[[UIDevice currentDevice]  systemVersion] floatValue] >= 8.0) {
            //调用此方法之前必须在plist文件中添加NSLocationWhenInUseUsageDescription --string-- 后面跟的文字就是提示信息
            [self.locationManager requestWhenInUseAuthorization];
        }
    }
}

- (void)addAnnotation {

    // 初始化大头针模型
    Annotation *anno1 = [[Annotation alloc] init];
    anno1.coordinate = CLLocationCoordinate2DMake(39, 116);
    anno1.title = @"xxx大饭店";
    anno1.subtitle = @"全场一律15折,会员20折";
    anno1.image = [UIImage imageNamed:@"category_1"];
    anno1.icon = [UIImage imageNamed:@"me"];
    anno1.detail = @"情侣入住,只收一个人的钱!";
    // 添加大头针模型
    [self.mapView addAnnotation:anno1];

    Annotation *anno2 = [[Annotation alloc] init];
    anno2.coordinate = CLLocationCoordinate2DMake(40, 117);
    anno2.title = @"xxx影院";
    anno2.subtitle = @"最新大片:美国队长2,即将上映。。。";
    anno2.image = [UIImage imageNamed:@"category_5"];
    anno2.icon = [UIImage imageNamed:@"other"];
    anno2.detail = @"情侣套票,只提供一个座位,你们可以正大光明的抱着!";
    [self.mapView addAnnotation:anno2];
}

#pragma mark - MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

    if ([annotation isKindOfClass:[Annotation class]]) {
        // 初始化大头针视图
        AnnotationView *annoView = [AnnotationView annotationViewWithMapView:mapView];
        annoView.animatesDrop = YES;
        // 传入大头针数据
        annoView.annotation = annotation;

        return annoView;
    }else if ([annotation isKindOfClass:[CalloutAnnotation class]]) {

        // 初始化大头针弹出视图
        // 对于作为弹出详情视图的自定义大头针视图无弹出交互功能,在其中可以自由添加其他视图(因为它本身继承于UIView)
        CalloutAnnotationView *calloutAnnoView = [CalloutAnnotationView annotationViewWithMapView:mapView];
        // 传入大头针模型数据
        calloutAnnoView.annotation = annotation;

        return calloutAnnoView;
    }
    return nil;
}

// 点击大头针视图时调用此方法,我们可以在这里添加大头针的详情视图
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {

    // 选中的是大头针视图:AnnotationView
    if ([view isKindOfClass:[AnnotationView class]]) {

        // 删除之前的大头针已经显示的详情视图,避免看到多个详情视图
        [self removeCustomAnnotation];

        // 获取点击的大头针数据
        Annotation *anno = (Annotation *)view.annotation;

        // 添加新的大头针详情数据
        CalloutAnnotation *calloutAnno = [[CalloutAnnotation alloc] init];
        // 获取数据模型 点击的大头针的数据就是需要添加的大头针数据
        calloutAnno.title = anno.title;
        calloutAnno.subtitle = anno.subtitle;
        calloutAnno.coordinate = anno.coordinate;
        calloutAnno.icon = anno.icon;
        calloutAnno.detail = anno.detail;
        // 添加大头针到地图
        [mapView addAnnotation:calloutAnno];
    }
}

// 重复点击时为取消选中大头针视图,会调用该方法
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view {
    // 移除所有的自定义弹出视图
    [self removeCustomAnnotation];
}

- (void)removeCustomAnnotation {

    // 遍历地图上的所有的大头针,删除之前的大头针已经显示的详情视图,避免看到多个详情视图
    [self.mapView.annotations enumerateObjectsUsingBlock:^(id<MKAnnotation>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj isKindOfClass:[CalloutAnnotation class]]) {
            [self.mapView removeAnnotation:obj];
        }
    }];
}

/**
 *  用户位置发生改变的时候调用这个方法
 *
 *  @param mapView      地图
 *  @param userLocation 地图上蓝色的那颗大头针数据(注意不是那个蓝色的视图)不复写该方法也可以显示
 */
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    userLocation.title = @"北京市";
    userLocation.subtitle = @"天朝帝都";
    NSLog(@"%f , %f",userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude);
    NSLog(@"%@",userLocation);

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        //设置地图显示的区域
        //获取中心点位置
        CLLocationCoordinate2D center = userLocation.location.coordinate;
        //显示跨度
        MKCoordinateSpan span = MKCoordinateSpanMake(3, 3*(375/667));
        //region
        MKCoordinateRegion region = MKCoordinateRegionMake(center,  span);
        [mapView setRegion:region animated:YES];

        [self addAnnotation];
    });
}
@end

猜你喜欢

转载自blog.csdn.net/qq_32510689/article/details/51727498