iOS学习笔记-地图MapKit入门
这篇文章还是翻译自raywenderlich,用Objective-C改写了代码。没有逐字翻译,如有错漏,请指出。原文地址在这里。
1 概述
MapKit是iOS提供的一个很便捷的API,旨在帮助我们快速开发地理位置相关的应用。在这篇博客中涉及的地方叫Honolulu,是美国的一个城市,中文名是檀香山,是美国夏威夷州首府和港口城市。我第一次听说檀香山应该是在历史书上,似乎跟孙中山先生相关,这里暂时按下不表。
本文的例子中我们要添加一个地图到APP中,然后通过经纬度定位到一个指定的位置,通过大头针的形式来展示定位,点击大头针会显示位置的一些信息。我们可以设置大头针的颜色,当然我们更可以自定义图片来替换默认的大头针,丰富地图内容。
2 开始
首先新建工程,命名为MapKitTutorial,然后添加一个Map Kit View到Storyboard中。先拖拽地图视图到充满屏幕,然后选择添加建议的约束即可,添加完约束效果如图1所示。
然后需要在ViewController.m
中添加Map View的outlet关联,通过CTRL+DRAG即可,命名为mapView,代码如下,别忘记引入MapKit头文件,注意要先导入MapKit库(Xcode7.3里面,先选择工程,然后在Capabilities那一项把Maps开关打开):
......
#import <MapKit/MapKit.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@end
这样,我们编译运行项目,可以看到地图出现了,默认显示的是中国地图在中央位置,这个应该是跟系统环境相关。如图2所示:
3 设置可视区域
接下来重点来了,我们要设置一个可视区域。学过地理
的都知道(我是地理盲),一个地理位置我们是通过纬度和经度来确定一个位置,纬度中北纬和南纬各分为90度,经度西经和东经则各为180度。在iOS开发中,北纬和东经我们用正数表示,南纬和西经用负数表示。
接下来我们要设置一个可视区域,不设置我们看到的只是一个默认区域,如前面看到的一样。设置可视区域的代码如下,然后在方法viewDidLoad中加入调用:
- (void)centerMapOnLocation {
//1 设置好纬度和经度
CLLocationCoordinate2D initialLocation = {21.282778, -157.829444};
CLLocationDistance regionRadius = 1000;
MKCoordinateRegion coordinateRegion = MKCoordinateRegionMakeWithDistance(initialLocation, regionRadius * 2, regionRadius * 2);
[self.mapView setRegion:coordinateRegion];
}
这里来解析一下,首先是设置好中心点的经纬度。然后是设置区域半径,包括横向和纵向半径,这里都设置的为2000米(南北和东西的跨度范围)。接着根据中心点经纬度和区域半径创建一个Region,最后调用MapView的setRegion方法即可。这时我们再运行代码可以看到效果如图3所示,我们看到与前面不同了,确实地图已经定位到我们设置的中心点和区域大小了:
4 设置标记
接下来来设置一个标记,也就是通常见到的那种大头针。先新建一个类Artwork来表示标记内容,包括位置坐标,标题和副标题等。位置坐标用于确定大头针位置,而标题和副标题则是点击大头针的时候显示的内容。
@interface Artwork : NSObject <MKAnnotation>
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property (nonatomic, strong) NSString *locationName;
@property (nonatomic, strong) NSString *discipline;
@property (nonatomic) CLLocationCoordinate2D coordinate;
- (instancetype)init:(NSString *)title
locationName:(NSString *)locationName
discipline:(NSString *)discipline
coordinate:(CLLocationCoordinate2D)coordinate;
@end
类Artwork定义如上所示,然后在ViewController.m中加入添加大头针的代码:
- (void)addAnnotation {
CLLocationCoordinate2D coordinate = {21.283921, -157.831661};
Artwork *artwork = [[Artwork alloc] init: @"King David Kalakaua"
locationName: @"Waikiki Gateway Park"
discipline: @"Sculpture"
coordinate: coordinate];
[self.mapView addAnnotation:artwork];
}
注意这里的坐标暂时是自己手动指定,在后面我们会从一个JSON文件中解析一系列的坐标位置然后设置多个大头针。然后里面的locationName其实是位置名字,而MKAnnotation是一个协议,地图标记的协议,它里面主要定义了一系列的属性值(这里可以发现协议不只有方法,也可以定义属性的),就是标记必须的几个属性title,subtitle,coordinate。
然后在viewDidLoad中加入该方法的调用,可以看到大头针显示,点击可以看到title和subtitle的显示。
仅仅这样当然是不够的,为了APP的个性化,我们希望可以自定义大头针显示方式,可以通过设置ViewController实现协议MKMapViewDelegate
,然后将mapView的delegate设置为ViewController,并在ViewController中实现协议的viewForAnnotation方法即可。代码如下:
- (void)viewDidLoad {
[super viewDidLoad];
[self centerMapOnLocation];
[self addAnnotation];
//1新增delegate设置
self.mapView.delegate = self;
}
//2 新增代理方法实现
#pragma MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[Artwork class]]) {
NSString *identifier = @"pin";
MKPinAnnotationView *view = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!view) {
view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
//自定义后需要设置canShowCallout为YES,不然点击不会显示信息。
view.canShowCallout = YES;
//设置信息展示偏移
view.calloutOffset = CGPointMake(-10, 5);
//设置信息按钮
view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
//设置大头针颜色
view.pinTintColor = [UIColor blueColor];
return view;
}
return nil;
}
方法viewForAnnotation中我们定义了大头针的信息偏移和在显示内容中添加了一个信息按钮。偏移位置是针对大头针的中间顶部而言的,这里我们设置信息展示的X轴向左偏移中间位置10个Point,Y轴则从顶部往下移动5个Point,并将大头针的颜色设置为蓝色,运行效果如图5所示。
5 启动地图APP
上一节点击信息按钮,并没有反应,接下来就要加入点击信息按钮的事件响应,这里我们是跳转到地图app中,显示从当前位置到公园的驾驶路线。
首先需要在类Artwork中加入一个方法,用来创建MapItem。这里需要导入Contacts头文件(原文中用的是Address头文件,iOS9以后的系统中已经不用Address,所以我这里用Contacts来替代)。
#import <Contacts/Contacts.h>
- (MKMapItem *)mapItem {
NSDictionary *addressDictionary = @{CNPostalAddressStreetKey: self.locationName};
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:self.coordinate addressDictionary:addressDictionary];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
return mapItem;
}
然后在ViewController中实现另外一个协议方法如下。另外,在Xcode菜单栏的Product\Scheme\Edit Scheme
选择Run的Options选项,设置好默认位置为Honolulu,如图6所示。这样点击右侧的信息按钮,就会跳转到地图APP中了(这里可能是由于高德地图问题,显示不了驾驶路线,暂时没有找到解决方法,若有知道的,麻烦告知一声)。
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
Artwork *artwork = (Artwork *)view.annotation;
NSDictionary *launchOptions = @{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving};
[[artwork mapItem] openInMapsWithLaunchOptions:launchOptions];
}
运行效果如下:
6 用户位置授权
在iOS应用中,如果应用要请求位置信息,一般是需要提示用户是否授权的,这个功能怎么实现呢?首先在ViewController中加入CLLocationManager,然后在viewDidAppear中加入请求授权的函数调用,如果一次请求授权允许了,系统会记录授权的状态,下次启动应用就不需要再次授权了。如果拒绝授权了,以后要开启只能到系统设置里面开启。
注意:一般请求授权分为两种方式,一种是requestWhenInUseAuthorization表示只有应用在前台允许的时候获取位置信息,而另外一种是requestAlwaysAuthorization表示只要应用在运行就可以获取位置信息,不管在前台还是后台运行,为了不泄露隐私,苹果官方是建议用第一种,即在前台运行的时候运行访问位置信息。
另外一个容易忽视的一点,就是还需要在项目的Info.plist中加入一个配置。配置键名为NSLocationWhenInUseUsageDescription
,内容为请求授权的文字信息,本项目填的信息为To show you cool things nearby
。
@property (strong, nonatomic) CLLocationManager *locationManager;
- (void)checkLocationStatus {
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) {
self.mapView.showsUserLocation = YES;
} else {
[self.locationManager requestWhenInUseAuthorization];
}
}
这样在启动应用的时候,就会弹出一个提示框,内容为应用请求访问您的位置信息,让你决定是否授权。效果如图8所示:
7 其他
原文中还有一节是通过一个JSON文件来设置多个大头针,并根据位置信息不同设置不同的大头针的颜色,与设置一个大头针效果类似,只是多了JSON解析的步骤,这里不再赘述,可以参见我的项目最终代码。
另外,地图里面还可以设置覆盖层(overlay),比如用图片来设置覆盖层,或者设置路径,多边形等,可以源码包看看。
8 项目文件截图
iOS学习笔记-地图MapKit入门
注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权
iOS学习笔记-地图MapKit入门的更多相关文章
- iOS学习笔记11-多线程入门
一.iOS多线程 iOS多线程开发有三种方式: NSThread NSOperation GCD iOS在每个进程启动后都会创建一个主线程,更新UI要在主线程上,所以也称为UI线程,是其他线程的父线程 ...
- iOS学习笔记20-地图(二)MapKit框架
一.地图开发介绍 从iOS6.0开始地图数据不再由谷歌驱动,而是改用自家地图,当然在国内它的数据是由高德地图提供的. 在iOS中进行地图开发主要有三种方式: 利用MapKit框架进行地图开发,利用这种 ...
- iOS学习笔记-精华整理
iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...
- iOS学习笔记总结整理
来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...
- IOS学习笔记48--一些常见的IOS知识点+面试题
IOS学习笔记48--一些常见的IOS知识点+面试题 1.堆和栈什么区别? 答:管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制:对于堆来说,释放工作由程序员控制,容易产生memor ...
- iOS学习笔记——AutoLayout的约束
iOS学习笔记——AutoLayout约束 之前在开发iOS app时一直以为苹果的布局是绝对布局,在IB中拖拉控件运行或者直接使用代码去调整控件都会发上一些不尽人意的结果,后来发现iOS在引入了Au ...
- IOS学习笔记25—HTTP操作之ASIHTTPRequest
IOS学习笔记25—HTTP操作之ASIHTTPRequest 分类: iOS2012-08-12 10:04 7734人阅读 评论(3) 收藏 举报 iosios5网络wrapper框架新浪微博 A ...
- IOS学习笔记之关键词@dynamic
IOS学习笔记之关键词@dynamic @dynamic这个关键词,通常是用不到的. 它与@synthesize的区别在于: 使用@synthesize编译器会确实的产生getter和setter方法 ...
- iOS学习笔记10-UIView动画
上次学习了iOS学习笔记09-核心动画CoreAnimation,这次继续学习动画,上次使用的CoreAnimation很多人感觉使用起来很繁琐,有没有更加方便的动画效果实现呢?答案是有的,那就是UI ...
随机推荐
- 走进Spark--云计算大数据新一代技术
什么是Spark? 当然这里说的Spark指的是Apache Spark, Apache Spark™ is a fast and general engine for large-scale dat ...
- 洛谷 P1598 垂直柱状图【字符串】
题目描述 写一个程序从输入文件中去读取四行大写字母(全都是大写的,每行不超过72个字符),然后用柱状图输出每个字符在输入文件中出现的次数.严格地按照输出样例来安排你的输出格式. 输入输出格式 输入格式 ...
- hdu6127
hdu6127 题意 二维平面上存在一些点,每个点都有权值,任意两点组成的线段的权值为这两点权值的乘积,选定一条经过原点的直线,问怎样使得它经过的线段的权值之和最大. 分析 题目等价于用一条直线将平面 ...
- 洛谷——P1163 银行贷款
P1163 银行贷款 题目描述 当一个人从银行贷款后,在一段时间内他(她)将不得不每月偿还固定的分期付款.这个问题要求计算出贷款者向银行支付的利率.假设利率按月累计. 输入输出格式 输入格式: 输入文 ...
- 12、Django实战第12天:课程机构列表页数据展示
今天完成的是课程机构列表页.... 1.启动服务,进入xadmin后,添加5个城市信息用作测试数据 2.添加课程机构,其中有一项要上传封面图的地方要注意 封面图上传路径是我们在models中设置好的 ...
- [BZOJ4897][THUSC2016]成绩单(DP)
4897: [Thu Summer Camp2016]成绩单 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 220 Solved: 132[Subm ...
- 3.4常用类(java学习笔记)Math和Random
一.Math 这个类包含执行指数.对数.平方根法.三角函数等基本的数字运算. Math中还包含一些静态常量供我们调用. 如PI圆周率,E. 1.abs(),返回该数的绝对值. public class ...
- jdk_配置
如果不知道jdk安装目录,可以使用如下命令查找到jdk安装目录 linux /usr/libexec/java_home windows版 新建系统变量JAVA_HOME(自己jdk的安装目录)C:\ ...
- JQuery给动态HTML绑定事件
说明:涉及到事件委托原理,这里不深究了. 直接使用live或者delegate去实现.网上说on也可以,没测试过. 注意:live在新版的JQuery已经取消.on在比较新的版本才支持. 参考: ht ...
- Jackson使用ObjectManage#readValue传入泛型T的问题
说明:没找到合适的方法,持续关注这个问题 参考: https://stackoverflow.com/questions/11664894/jackson-deserialize-using-gene ...