文档章节

iOS开发系列--地图

_短发控
 _短发控
发布于 2016/01/19 12:04
字数 5537
阅读 10
收藏 0

地图


在iOS中进行地图开发主要有两种方式,一种是直接利用MapKit框架进行地图开发,利用这种方式可以对地图进行精准的控制;另一种方式是直接调用苹果官方自带的地图应用,主要用于一些简单的地图应用

用MapKit之前需要简单了解一下MapKit中地图展示控件MKMapView的的一些常用属性和方法,具体如下表: 

属性 说明
userTrackingMode 跟踪类型,是一个枚举:
MKUserTrackingModeNone :不进行用户位置跟踪;
MKUserTrackingModeFollow :跟踪用户位置;
MKUserTrackingModeFollowWithHeading :跟踪用户位置并且跟踪用户前进方向;
mapType 地图类型,是一个枚举:
MKMapTypeStandard :标准地图,一般情况下使用此地图即可满足;
MKMapTypeSatellite :卫星地图;
MKMapTypeHybrid :混合地图,加载最慢比较消耗资源;
userLocation 用户位置,只读属性
annotations 当前地图中的所有大头针,只读属性
对象方法 说明
- (void)addAnnotation:(id <MKAnnotation>)annotation; 添加大头针,对应的有添加大头针数组
- (void)removeAnnotation:(id <MKAnnotation>)annotation; 删除大头针,对应的有删除大头针数组

- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;

设置地图显示区域,用于控制当前屏幕显示地图范围
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated; 设置地图中心点位置
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view; 将地理坐标(经纬度)转化为数学坐标(UIKit坐标)
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view; 将数学坐标转换为地理坐标
- (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier; 从缓存池中取出大头针,类似于UITableView中取出UITableViewCell,为了进行性能优化而设计
- (void)selectAnnotation:(id <MKAnnotation>)annotation animated:(BOOL)animated; 选中指定的大头针
- (void)deselectAnnotation:(id <MKAnnotation>)annotation animated:(BOOL)animated; 取消选中指定的大头针
代理方法 说明
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation ; 用户位置发生改变时触发(第一次定位到用户位置也会触发该方法)
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation ; 显示区域发生改变后触发
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView; 地图加载完成后触发
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation; 显示大头针时触发,返回大头针视图,通常自定义大头针可以通过此方法进行
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view  点击选中某个大头针时触发
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view 取消选中大头针时触发
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay 渲染地图覆盖物时触发

用户位置跟踪

在很多带有地图的应用中默认打开地图都会显示用户当前位置,同时将当前位置标记出来放到屏幕中点方便用户对周围情况进行查看。如果在iOS6或者iOS7中实现这个功能只需要添加地图控件、设置用户跟踪模式、在-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation代理方法中设置地图中心区域及显示范围。但是在iOS8中用法稍有不同:

1.由于在地图中进行用户位置跟踪需要使用定位功能,而定位功能在iOS8中设计发生了变化,因此必须按照前面定位章节中提到的内容进行配置和请求。

2.iOS8中不需要进行中心点的指定,默认会将当前位置设置中心点并自动设置显示区域范围。

了解以上两点,要进行用户位置跟踪其实就相当简单了,值得一提的是-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation这个代理方法。这个方法只有在定位(利用前面章节中的定位内容)到当前位置之后就会调用,以后每当用户位置发生改变就会触发,调用频率相当频繁。

大头针

在iOS开发中经常会标记某个位置,需要使用地图标注,也就是大家俗称的“大头针”。只要一个NSObject类实现MKAnnotation协议就可以作为一个大头针,通常会重写协议中coordinate(标记位置)、title(标题)、subtitle(子标题)三个属性,然后在程序中创建大头针对象并调用addAnnotation:方法添加大头针即可(之所以iOS没有定义一个基类实现这个协议供开发者使用,多数原因应该是MKAnnotation是一个模型对象,对于多数应用模型会稍有不同,例如后面的内容中会给大头针模型对象添加其他属性)。

KCAnnotation.h

//
//  KCAnnotation.h
//  MapKit
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//#import <Foundation/Foundation.h>#import <MapKit/MapKit.h>@interface KCAnnotation : NSObject<MKAnnotation>

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

@end

KCMainViewController.m

//
//  KCMainViewController.m
//  MapKit Annotation
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//  37.785834   -122.406417
//  39.92 116.39#import "KCMainViewController.h"#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>#import "KCAnnotation.h"@interface KCMainViewController ()<MKMapViewDelegate>{
    CLLocationManager *_locationManager;
    MKMapView *_mapView;
}

@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self initGUI];
}#pragma mark 添加地图控件
-(void)initGUI{
    CGRect rect=[UIScreen mainScreen].bounds;
    _mapView=[[MKMapView alloc]initWithFrame:rect];
    [self.view addSubview:_mapView];    //设置代理    _mapView.delegate=self;    
    //请求定位服务    _locationManager=[[CLLocationManager alloc]init];    if(![CLLocationManager locationServicesEnabled]||[CLLocationManager authorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){
        [_locationManager requestWhenInUseAuthorization];
    }    
    //用户位置追踪(用户位置追踪用于标记用户当前位置,此时会调用定位服务)    _mapView.userTrackingMode=MKUserTrackingModeFollow;    
    //设置地图类型    _mapView.mapType=MKMapTypeStandard;    
    //添加大头针    [self addAnnotation];
}#pragma mark 添加大头针 
-(void)addAnnotation{
    CLLocationCoordinate2D location1=CLLocationCoordinate2DMake(39.95, 116.35);
    KCAnnotation *annotation1=[[KCAnnotation alloc]init];
    annotation1.title=@"CMJ Studio";
    annotation1.subtitle=@"Kenshin Cui's Studios";
    annotation1.coordinate=location1;
    [_mapView addAnnotation:annotation1];
    
    CLLocationCoordinate2D location2=CLLocationCoordinate2DMake(39.87, 116.35);
    KCAnnotation *annotation2=[[KCAnnotation alloc]init];
    annotation2.title=@"Kenshin&Kaoru";
    annotation2.subtitle=@"Kenshin Cui's Home";
    annotation2.coordinate=location2;
    [_mapView addAnnotation:annotation2];
}#pragma mark - 地图控件代理方法#pragma mark 更新用户位置,只要用户改变则调用此方法(包括第一次定位到用户位置)
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
    
    NSLog(@"%@",userLocation);    //设置地图显示范围(如果不进行区域设置会自动显示区域范围并指定当前用户位置为地图中心点)
    //    MKCoordinateSpan span=MKCoordinateSpanMake(0.01, 0.01);
    //    MKCoordinateRegion region=MKCoordinateRegionMake(userLocation.location.coordinate, span);
    //    [_mapView setRegion:region animated:true];}

@end

运行效果:

MapKit_Annotation 

设置大头针视图

在一些应用中系统默认的大头针样式可能无法满足实际的需求,此时就需要修改大头针视图默认样式。根据前面MapKit的代理方法不难发现- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;方法可以返回一个大头针视图,只要实现这个方法并在这个方法中定义一个大头针视图MKAnnotationView对象并设置相关属性就可以改变默认大头针的样式。MKAnnotationView常用属性:

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

需要注意:

a.这个代理方法的调用时机:每当有大头针显示到系统可视界面中时就会调用此方法返回一个大头针视图放到界面中,同时当前系统位置标注(也就是地图中蓝色的位置点)也是一个大头针,也会调用此方法,因此处理大头针视图时需要区别对待。

b.类似于UITableView的代理方法,此方法调用频繁,开发过程中需要重复利用MapKit的缓存池将大头针视图缓存起来重复利用。

c.自定义大头针默认情况下不允许交互,如果交互需要设置canShowCallout=true

d.如果代理方法返回nil则会使用默认大头针视图,需要根据情况设置。

下面以一个示例进行大头针视图设置,这里设置了大头针的图片、弹出视图、偏移量等信息。

KCAnnotation.h

//
//  KCAnnotation.h
//  MapKit
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//#import <Foundation/Foundation.h>#import <MapKit/MapKit.h>@interface KCAnnotation : NSObject<MKAnnotation>

@property (nonatomic) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;#pragma mark 自定义一个图片属性在创建大头针视图时使用
@property (nonatomic,strong) UIImage *image;

@end

KCMainViewController.m

//
//  KCMainViewController.m
//  MapKit Annotation
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//  37.785834   -122.406417
//  39.92 116.39#import "KCMainViewController.h"#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>#import "KCAnnotation.h"@interface KCMainViewController ()<MKMapViewDelegate>{
    CLLocationManager *_locationManager;
    MKMapView *_mapView;
}

@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self initGUI];
}#pragma mark 添加地图控件
-(void)initGUI{
    CGRect rect=[UIScreen mainScreen].bounds;
    _mapView=[[MKMapView alloc]initWithFrame:rect];
    [self.view addSubview:_mapView];    //设置代理    _mapView.delegate=self;    
    //请求定位服务    _locationManager=[[CLLocationManager alloc]init];    if(![CLLocationManager locationServicesEnabled]||[CLLocationManager authorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){
        [_locationManager requestWhenInUseAuthorization];
    }    
    //用户位置追踪(用户位置追踪用于标记用户当前位置,此时会调用定位服务)    _mapView.userTrackingMode=MKUserTrackingModeFollow;    
    //设置地图类型    _mapView.mapType=MKMapTypeStandard;    
    //添加大头针    [self addAnnotation];
}#pragma mark 添加大头针 
-(void)addAnnotation{
    CLLocationCoordinate2D location1=CLLocationCoordinate2DMake(39.95, 116.35);
    KCAnnotation *annotation1=[[KCAnnotation alloc]init];
    annotation1.title=@"CMJ Studio";
    annotation1.subtitle=@"Kenshin Cui's Studios";
    annotation1.coordinate=location1;
    annotation1.image=[UIImage imageNamed:@"icon_pin_floating.png"];
    [_mapView addAnnotation:annotation1];
    
    CLLocationCoordinate2D location2=CLLocationCoordinate2DMake(39.87, 116.35);
    KCAnnotation *annotation2=[[KCAnnotation alloc]init];
    annotation2.title=@"Kenshin&Kaoru";
    annotation2.subtitle=@"Kenshin Cui's Home";
    annotation2.coordinate=location2;
    annotation2.image=[UIImage imageNamed:@"icon_paopao_waterdrop_streetscape.png"];
    [_mapView addAnnotation:annotation2];
}#pragma mark - 地图控件代理方法#pragma mark 显示大头针时调用,注意方法中的annotation参数是即将显示的大头针对象
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{    //由于当前位置的标注也是一个大头针,所以此时需要判断,此代理方法返回nil使用默认大头针视图    if ([annotation isKindOfClass:[KCAnnotation class]]) {        static NSString *key1=@"AnnotationKey1";
        MKAnnotationView *annotationView=[_mapView dequeueReusableAnnotationViewWithIdentifier:key1];        //如果缓存池中不存在则新建        if (!annotationView) {
            annotationView=[[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:key1];
            annotationView.canShowCallout=true;//允许交互点击            annotationView.calloutOffset=CGPointMake(0, 1);//定义详情视图偏移量            annotationView.leftCalloutAccessoryView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"icon_classify_cafe.png"]];//定义详情左侧视图        }        //修改大头针视图
        //重新设置此类大头针视图的大头针模型(因为有可能是从缓存池中取出来的,位置是放到缓存池时的位置)        annotationView.annotation=annotation;
        annotationView.image=((KCAnnotation *)annotation).image;//设置大头针视图的图片        
        return annotationView;
    }else {        return nil;
    }
}
@end

运行效果:

MapKit_CustomeAnnotationImage


扩展--自定义大头针弹详情视图

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

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

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

在使用百度地图客户端时当点击一个搜索位置时可以看到此位置的评价等信息,视图效果大概如下:

Baidu_CalloutView 

下面不妨试着实现一下这个效果:

大头针模型:KCAnnotation.h

//
//  KCAnnotation.h
//  MapKit
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//#import <Foundation/Foundation.h>#import <MapKit/MapKit.h>@interface KCAnnotation : NSObject<MKAnnotation>

@property (nonatomic) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;#pragma mark 自定义一个图片属性在创建大头针视图时使用
@property (nonatomic,strong) UIImage *image;#pragma mark 大头针详情左侧图标
@property (nonatomic,strong) UIImage *icon;#pragma mark 大头针详情描述 
@property (nonatomic,copy) NSString *detail;#pragma mark 大头针右下方星级评价
@property (nonatomic,strong) UIImage *rate;

@end

弹出详情大头针模型:KCCalloutAnnotation.h

//
//  KCCalloutAnnotation.h
//  MapKit
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//#import <UIKit/UIKit.h>#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>@interface KCCalloutAnnotation : NSObject<MKAnnotation>

@property (nonatomic) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy,readonly) NSString *title;
@property (nonatomic, copy,readonly) NSString *subtitle;#pragma mark 左侧图标
@property (nonatomic,strong) UIImage *icon;#pragma mark 详情描述
@property (nonatomic,copy) NSString *detail;#pragma mark 星级评价
@property (nonatomic,strong) UIImage *rate;

@end

弹出详情大头针视图:KCCalloutAnnotatonView.h

//
//  KCCalloutView.h
//  MapKit
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//  自定义弹出标注视图#import <UIKit/UIKit.h>#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>#import "KCCalloutAnnotation.h"@interface KCCalloutAnnotationView : MKAnnotationView

@property (nonatomic ,strong) KCCalloutAnnotation *annotation;#pragma mark 从缓存取出标注视图
+(instancetype)calloutViewWithMapView:(MKMapView *)mapView;

@end

KCCalloutAnnotationView.m

//
//  KCCalloutView.m
//  MapKit
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//#import "KCCalloutAnnotationView.h"#define kSpacing 5#define kDetailFontSize 12#define kViewOffset 80

@interface KCCalloutAnnotationView(){
    UIView *_backgroundView;
    UIImageView *_iconView;
    UILabel *_detailLabel;
    UIImageView *_rateView;
}

@end

@implementation KCCalloutAnnotationView

-(instancetype)init{    if(self=[super init]){
        [self layoutUI];
    }    return self;
}
-(instancetype)initWithFrame:(CGRect)frame{    if (self=[super initWithFrame:frame]) {
        [self layoutUI];
    }    return self;
}

-(void)layoutUI{    //背景    _backgroundView=[[UIView alloc]init];
    _backgroundView.backgroundColor=[UIColor whiteColor];    //左侧添加图标    _iconView=[[UIImageView alloc]init];    
    //上方详情    _detailLabel=[[UILabel alloc]init];
    _detailLabel.lineBreakMode=NSLineBreakByWordWrapping;    //[_text sizeToFit];    _detailLabel.font=[UIFont systemFontOfSize:kDetailFontSize];    
    //下方星级    _rateView=[[UIImageView alloc]init];
    
    [self addSubview:_backgroundView];
    [self addSubview:_iconView];
    [self addSubview:_detailLabel];
    [self addSubview:_rateView];
}

+(instancetype)calloutViewWithMapView:(MKMapView *)mapView{    static NSString *calloutKey=@"calloutKey1";
    KCCalloutAnnotationView *calloutView=(KCCalloutAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:calloutKey];    if (!calloutView) {
        calloutView=[[KCCalloutAnnotationView alloc]init];
    }    return calloutView;
}#pragma mark 当给大头针视图设置大头针模型时可以在此处根据模型设置视图内容
-(void)setAnnotation:(KCCalloutAnnotation *)annotation{
    [super setAnnotation:annotation];    //根据模型调整布局    _iconView.image=annotation.icon;
    _iconView.frame=CGRectMake(kSpacing, kSpacing, annotation.icon.size.width, annotation.icon.size.height);
    
    _detailLabel.text=annotation.detail;    float detailWidth=150.0;
    CGSize detailSize= [annotation.detail boundingRectWithSize:CGSizeMake(detailWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kDetailFontSize]} context:nil].size;    float detailX=CGRectGetMaxX(_iconView.frame)+kSpacing;
    _detailLabel.frame=CGRectMake(detailX, kSpacing, detailSize.width, detailSize.height);
    _rateView.image=annotation.rate;
    _rateView.frame=CGRectMake(detailX, CGRectGetMaxY(_detailLabel.frame)+kSpacing, annotation.rate.size.width, annotation.rate.size.height);    
    float backgroundWidth=CGRectGetMaxX(_detailLabel.frame)+kSpacing;    float backgroundHeight=_iconView.frame.size.height+2*kSpacing;
    _backgroundView.frame=CGRectMake(0, 0, backgroundWidth, backgroundHeight);
    self.bounds=CGRectMake(0, 0, backgroundWidth, backgroundHeight+kViewOffset);
    
}
@end

主视图控制器:KCMainViewController.m

//
//  KCMainViewController.m
//  MapKit Annotation
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//  37.785834   -122.406417
//  39.92 116.39#import "KCMainViewController.h"#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>#import "KCAnnotation.h"#import "KCCalloutAnnotationView.h"#import "KCCalloutAnnotationView.h"@interface KCMainViewController ()<MKMapViewDelegate>{
    CLLocationManager *_locationManager;
    MKMapView *_mapView;
}

@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self initGUI];
}#pragma mark 添加地图控件
-(void)initGUI{
    CGRect rect=[UIScreen mainScreen].bounds;
    _mapView=[[MKMapView alloc]initWithFrame:rect];
    [self.view addSubview:_mapView];    //设置代理    _mapView.delegate=self;    
    //请求定位服务    _locationManager=[[CLLocationManager alloc]init];    if(![CLLocationManager locationServicesEnabled]||[CLLocationManager authorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){
        [_locationManager requestWhenInUseAuthorization];
    }    
    //用户位置追踪(用户位置追踪用于标记用户当前位置,此时会调用定位服务)    _mapView.userTrackingMode=MKUserTrackingModeFollow;    
    //设置地图类型    _mapView.mapType=MKMapTypeStandard;    
    //添加大头针    [self addAnnotation];
}#pragma mark 添加大头针 
-(void)addAnnotation{
    CLLocationCoordinate2D location1=CLLocationCoordinate2DMake(39.95, 116.35);
    KCAnnotation *annotation1=[[KCAnnotation alloc]init];
    annotation1.title=@"CMJ Studio";
    annotation1.subtitle=@"Kenshin Cui's Studios";
    annotation1.coordinate=location1;
    annotation1.image=[UIImage imageNamed:@"icon_pin_floating.png"];
    annotation1.icon=[UIImage imageNamed:@"icon_mark1.png"];
    annotation1.detail=@"CMJ Studio...";
    annotation1.rate=[UIImage imageNamed:@"icon_Movie_Star_rating.png"];
    [_mapView addAnnotation:annotation1];
    
    CLLocationCoordinate2D location2=CLLocationCoordinate2DMake(39.87, 116.35);
    KCAnnotation *annotation2=[[KCAnnotation alloc]init];
    annotation2.title=@"Kenshin&Kaoru";
    annotation2.subtitle=@"Kenshin Cui's Home";
    annotation2.coordinate=location2;
    annotation2.image=[UIImage imageNamed:@"icon_paopao_waterdrop_streetscape.png"];
    annotation2.icon=[UIImage imageNamed:@"icon_mark2.png"];
    annotation2.detail=@"Kenshin Cui...";
    annotation2.rate=[UIImage imageNamed:@"icon_Movie_Star_rating.png"];
    [_mapView addAnnotation:annotation2];
}#pragma mark - 地图控件代理方法#pragma mark 显示大头针时调用,注意方法中的annotation参数是即将显示的大头针对象
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{    //由于当前位置的标注也是一个大头针,所以此时需要判断,此代理方法返回nil使用默认大头针视图    if ([annotation isKindOfClass:[KCAnnotation class]]) {        static NSString *key1=@"AnnotationKey1";
        MKAnnotationView *annotationView=[_mapView dequeueReusableAnnotationViewWithIdentifier:key1];        //如果缓存池中不存在则新建        if (!annotationView) {
            annotationView=[[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:key1];//            annotationView.canShowCallout=true;//允许交互点击            annotationView.calloutOffset=CGPointMake(0, 1);//定义详情视图偏移量            annotationView.leftCalloutAccessoryView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"icon_classify_cafe.png"]];//定义详情左侧视图        }        //修改大头针视图
        //重新设置此类大头针视图的大头针模型(因为有可能是从缓存池中取出来的,位置是放到缓存池时的位置)        annotationView.annotation=annotation;
        annotationView.image=((KCAnnotation *)annotation).image;//设置大头针视图的图片        
        return annotationView;
    }else if([annotation isKindOfClass:[KCCalloutAnnotation class]]){        //对于作为弹出详情视图的自定义大头针视图无弹出交互功能(canShowCallout=false,这是默认值),在其中可以自由添加其他视图(因为它本身继承于UIView)        KCCalloutAnnotationView *calloutView=[KCCalloutAnnotationView calloutViewWithMapView:mapView];
        calloutView.annotation=annotation;        return calloutView;
    } else {        return nil;
    }
}#pragma mark 选中大头针时触发//点击一般的大头针KCAnnotation时添加一个大头针作为所点大头针的弹出详情视图-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
    KCAnnotation *annotation=view.annotation;    if ([view.annotation isKindOfClass:[KCAnnotation class]]) {        //点击一个大头针时移除其他弹出详情视图
//        [self removeCustomAnnotation];
        //添加详情大头针,渲染此大头针视图时将此模型对象赋值给自定义大头针视图完成自动布局        KCCalloutAnnotation *annotation1=[[KCCalloutAnnotation alloc]init];
        annotation1.icon=annotation.icon;
        annotation1.detail=annotation.detail;
        annotation1.rate=annotation.rate;
        annotation1.coordinate=view.annotation.coordinate;
        [mapView addAnnotation:annotation1];
    }
}#pragma mark 取消选中时触发
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view{
    [self removeCustomAnnotation];
}#pragma mark 移除所用自定义大头针
-(void)removeCustomAnnotation{
    [_mapView.annotations enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {        if ([obj isKindOfClass:[KCCalloutAnnotation class]]) {
            [_mapView removeAnnotation:obj];
        }
    }];
}
@end

在这个过程中需要注意几点:

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

2.自定义大头针视图C的大头针模型B中不需要title、subtitle属性,最好设置为只读;模型中最后保存自定义大头针视图C所需要的布局模型数据。

3.只有点击非B类大头针时才新增自定义大头针,并且增加时要首先移除其他B类大头针避免重叠(一般建议放到取消大头针选择的代理方法中)。

4.通常在自定义大头针视图C设置大头针模型时布局界面,此时需要注意新增大头针的位置,通常需要偏移一定的距离才能达到理想的效果。

运行效果:

MapKit_CustomAnotationCalloutView2

使用自带的地图应用

除了可以使用MapKit框架进行地图开发,对地图有精确的控制和自定义之外,如果对于应用没有特殊要求的话选用苹果自带的地图应用也是一个不错的选择。使用苹果自带的应用时需要用到MapKit中的MKMapItem类,这个类有一个openInMapsWithLaunchOptions:动态方法和一个openMapsWithItems: launchOptions:静态方法用于打开苹果地图应用。第一个方法用于在地图上标注一个位置,第二个方法除了可以标注多个位置外还可以进行多个位置之间的驾驶导航,使用起来也是相当方便。在熟悉这两个方法使用之前有必要对两个方法中的options参数做一下简单说明:

键(常量) 说明
MKLaunchOptionsDirectionsModeKey 路线模式,常量 MKLaunchOptionsDirectionsModeDriving  驾车模式
MKLaunchOptionsDirectionsModeWalking 步行模式
MKLaunchOptionsMapTypeKey 地图类型,枚举 MKMapTypeStandard :标准模式
MKMapTypeSatellite :卫星模式
MKMapTypeHybrid  :混合模式
MKLaunchOptionsMapCenterKey 中心点坐标,CLLocationCoordinate2D类型
MKLaunchOptionsMapSpanKey 地图显示跨度,MKCoordinateSpan 类型
MKLaunchOptionsShowsTrafficKey 是否 显示交通状况,布尔型
MKLaunchOptionsCameraKey 3D地图效果,MKMapCamera类型
注意:此属性从iOS7及以后可用,前面的属性从iOS6开始可用

单个位置的标注

下面的代码演示了如何在苹果自带地图应用上标记一个位置,首先根据反地理编码获得一个CLPlacemark位置对象,然后将其转换为MKPlacemark对象用于MKMapItem初始化,最后调用其openInMapsWithLaunchOptions:打开地图应用并标记:

//
//  KCMainViewController.m
//  AppleMap
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//#import "KCMainViewController.h"#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>@interface KCMainViewController ()
@property (nonatomic,strong) CLGeocoder *geocoder;
@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _geocoder=[[CLGeocoder alloc]init];
    
    [self location];
}#pragma mark 在地图上定位
-(void)location{    //根据“北京市”进行地理编码    [_geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray *placemarks, NSError *error) {
        CLPlacemark *clPlacemark=[placemarks firstObject];//获取第一个地标        MKPlacemark *mkplacemark=[[MKPlacemark alloc]initWithPlacemark:clPlacemark];//定位地标转化为地图的地标        NSDictionary *options=@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};
        MKMapItem *mapItem=[[MKMapItem alloc]initWithPlacemark:mkplacemark];
        [mapItem openInMapsWithLaunchOptions:options];
    }];
}
@end

运行效果:

AppleMap_Placemark

标记多个位置

如果要标记多个位置需要调用MKMapItem的静态方法,下面的代码演示中需要注意,使用CLGeocoder进行定位时一次只能定位到一个位置,所以第二个位置定位放到了第一个位置获取成功之后。

//
//  KCMainViewController.m
//  AppleMap
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//#import "KCMainViewController.h"#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>@interface KCMainViewController ()
@property (nonatomic,strong) CLGeocoder *geocoder;
@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _geocoder=[[CLGeocoder alloc]init];
    
    [self listPlacemark];
}

-(void)listPlacemark{    //根据“北京市”进行地理编码    [_geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray *placemarks, NSError *error) {
        CLPlacemark *clPlacemark1=[placemarks firstObject];//获取第一个地标        MKPlacemark *mkPlacemark1=[[MKPlacemark alloc]initWithPlacemark:clPlacemark1];        //注意地理编码一次只能定位到一个位置,不能同时定位,所在放到第一个位置定位完成回调函数中再次定位        [_geocoder geocodeAddressString:@"郑州市" completionHandler:^(NSArray *placemarks, NSError *error) {
            CLPlacemark *clPlacemark2=[placemarks firstObject];//获取第一个地标            MKPlacemark *mkPlacemark2=[[MKPlacemark alloc]initWithPlacemark:clPlacemark2];
            NSDictionary *options=@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};            //MKMapItem *mapItem1=[MKMapItem mapItemForCurrentLocation];//当前位置            MKMapItem *mapItem1=[[MKMapItem alloc]initWithPlacemark:mkPlacemark1];
            MKMapItem *mapItem2=[[MKMapItem alloc]initWithPlacemark:mkPlacemark2];
            [MKMapItem openMapsWithItems:@[mapItem1,mapItem2] launchOptions:options];
            
        }];
        
    }];
}
@end

运行效果:

ApleMap_MultiPlacemark3

地图导航

要使用地图导航功能在自带地图应用中相当简单,只要设置参数配置导航模式即可,例如在上面代码基础上设置驾驶模式,则地图应用会启动驾驶模式计算两点之间的距离同时对路线进行规划。

//
//  KCMainViewController.m
//  AppleMap
//
//  Created by Kenshin Cui on 14/3/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//#import "KCMainViewController.h"#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>@interface KCMainViewController ()
@property (nonatomic,strong) CLGeocoder *geocoder;
@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _geocoder=[[CLGeocoder alloc]init];
    
    [self turnByTurn];
}

-(void)turnByTurn{    //根据“北京市”地理编码    [_geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray *placemarks, NSError *error) {
        CLPlacemark *clPlacemark1=[placemarks firstObject];//获取第一个地标        MKPlacemark *mkPlacemark1=[[MKPlacemark alloc]initWithPlacemark:clPlacemark1];        //注意地理编码一次只能定位到一个位置,不能同时定位,所在放到第一个位置定位完成回调函数中再次定位        [_geocoder geocodeAddressString:@"郑州市" completionHandler:^(NSArray *placemarks, NSError *error) {
            CLPlacemark *clPlacemark2=[placemarks firstObject];//获取第一个地标            MKPlacemark *mkPlacemark2=[[MKPlacemark alloc]initWithPlacemark:clPlacemark2];
            NSDictionary *options=@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard),MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving};            //MKMapItem *mapItem1=[MKMapItem mapItemForCurrentLocation];//当前位置            MKMapItem *mapItem1=[[MKMapItem alloc]initWithPlacemark:mkPlacemark1];
            MKMapItem *mapItem2=[[MKMapItem alloc]initWithPlacemark:mkPlacemark2];
            [MKMapItem openMapsWithItems:@[mapItem1,mapItem2] launchOptions:options];
            
        }];
        
    }];
}
@end

CLLocation:用于表示位置信息,包含地理坐标、海拔等信息,包含在CoreLoaction框架中。

MKUserLocation:一个特殊的大头针,表示用户当前位置。

CLPlacemark:定位框架中地标类,封装了详细的地理信息。

MKPlacemark:类似于CLPlacemark,只是它在MapKit框架中,可以根据CLPlacemark创建MKPlacemark。


本文转载自:http://www.cnblogs.com/kenshincui/p/4125570.html

上一篇: QQ好友列表
_短发控
粉丝 1
博文 11
码字总数 3669
作品 0
西峰
私信 提问
ArcGIS for iOS 开发系列(1) – 基本概念

1.1 iOS简介 2006年苹果公司发布了智能手机iPhone,卓越的外形设计和新颖的触摸式交互,令其迅速风靡全球,随后发布的平板电脑iPad同样也取得了巨大成功,二者所搭载的都是iOS智能移动操作系...

长平狐
2012/11/28
867
0
ArcGIS for iOS 开发系列(2) – 开发环境配置

我们已经掌握了一些基本知识,在动手编程之前,还需先配置下开发环境: 2.1 iOS 配置 1) Mac电脑(MacBook Air/ Pro、Mac mini和iMac都可以); 2) Snow Leopard(小版本10.6.2以上)、Lio...

长平狐
2012/11/28
1K
0
谷歌发布视频广告招募iOS应用开发者

新浪科技讯 北京时间12月30日上午消息,谷歌本周为其内部iOS开发团队发布了一段视频招聘广告,希望进一步增强该团队的实力。这表明谷歌不仅要在Android平台上与苹果竞争,还要在苹果自己的平...

oschina
2012/12/31
1K
7
Google 或于今天发布 iOS 版地图

Google地图一直预装在iPhone中,但是在9月份发布的iOS 6中,苹果使用了自己开发的地图,放弃了Google地图。不过,苹果地图显然是仓促上线,问题多多。不少用户希望能重新使用Google地图,一个...

oschina
2012/12/13
2.7K
12
ios 有没有做GIS的开源SDK或软件?

最近想做一款GIS的应用程序,部署在ipad硬件上;但我不知道怎么入手。就是在ipad上能够显示地图、导航,采集,标注等功能的GIS软件。 查找了许多资料都是基于ARCGIS API for ios;baidu API ...

ios与GIS新手
2012/12/06
1K
4

没有更多内容

加载失败,请刷新页面

加载更多

mysql已存在的表增加自增字段

需求: 已有的mysql数据表,希望增加一个自增的字段,并设置新数据的初始值。 实际上不复杂,只是做个备忘。 测试表 CREATE TABLE `t_abc` ( `name` varchar(20) DEFAULT NULL) ENGINE=In...

polly
27分钟前
1
0
去掉截屏功能

/home/rk3288_600_f703/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java 有一个截屏的线程,注释掉...

安卓工程师王恒
36分钟前
0
0
解决vim打开之后乱码的问题

在Windows中的文档,传输到Linux系统中(使用rz命令),出现乱码 root@localhost ~]# rpm -qf `which iconv` glibc-common-2.17-105.el7.x86_64 [root@localhost ~]# rpm -ihv /mnt/Packages......

寰宇01
53分钟前
2
0
aldi 2017年1月记录

../../tools/CBLAS/lib/cblas_LINUX.a ../../tools/lapack-3.4.2/liblapacke.a \../../tools/lapack-3.4.2/librefblas.a -lgfortran \../../tools/lapack-3.4.2/liblapack.a \../../......

MtrS
54分钟前
3
0
Choerodon如何进行日志收集与告警

作者:董文启 应用程序日志是由软件应用程序记录的事件文件, 它一般包含错误,信息事件和警告。一个良好的日志系统有助于快速发现问题,定位问题,同时也为业务分析起到一定的作用。 传统E...

Choerodon
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部