在iOS的应用中,有很多的应用都是使用了核心定位功能和地图的相关功能!
在实际开发中,也有很多相关的针对地图和定位来做的第三方插件!比如:百度地图。
关于第三方地图和定位插件,也是利用iOS中的相关API做的扩展和整合。具体,使用第三方的插件,就需要了解它们的API。
今天了解的就是iOS原始的核心定位和地图API!
什么是核心定位和地图
Core Location 以及 Map 框架包通常能给我们的应用程序添加定位和地图相关的服务。
Core Location 框架包通常是使用硬件设备来进行定位服务的,Map 框架包通常能够使你的应用程序做一些地图展示与交互的相关功能。
iOS将这两个功能封装到了两个库中。当然,我们需要在项目中引入该库,才能享受相应的服务。
这两个库分别是:
核心定位: #import
地图: #import
一、添加一个简单的地图视图
*.h 文件
#import
#import
#import
@interface MoreViewController : UIViewController<MKMapViewDelegate,CLLocationManagerDelegate>{
}
@property (nonatomic, strong) MKMapView *myMapView;
@end
*.m 文件
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
// 初始化MKMapView
self.myMapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
self.myMapView.mapType = MKMapTypeHybrid;
[self.myMapView setDelegate:self];
self.myMapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.myMapView];
// 返回用户是否开启了设备上的“定位服务”功能
if ([CLLocationManager locationServicesEnabled]){
self.myLocationManager = [[CLLocationManager alloc] init];
[self.myLocationManager setDelegate:self];
[self.myLocationManager setPurpose:@"一些提示信息,告诉用户要开启定位服务功能"];
// 开始更新地理位置,并根据更新结果执行CLLocationManagerDelegate方法
[self.myLocationManager startUpdatingLocation];
} else {
NSLog(@"设备上的“定位服务”功能未开启!");
}
}
说明:
在VC中,我们实现了两个协议,来捕捉相应的事件:
MKMapViewDelegate:关于地图的相关协议,定义了地图相关的协议方法。
CLLocationManagerDelegate:关于核心定位的相关协议。
这两个协议有很多方法,慢慢来体会吧。
二、为地图定义锚点
为了更好的封装性,我们自定义了一个锚点的自定义类,来控制锚点。
忽然有点迷茫,为什么要自定义锚点类呢?
@interface MyAnnotation : NSObject <MKAnnotation>
因为MKAnnotation协议中的属性都是只读的!我们要方便的设置,就必须要覆盖MKAnnotation协议中的属性。
*.h 文件
#import
#import
@interface MyAnnotation : NSObject <MKAnnotation>{
}
// 特别要注意这个参数需要标示为只读类型的。因为 MKAnnotation 这个协议中定义的 Coordinate 也是只读类型的。
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy, readonly) NSString *title;
@property (nonatomic, copy, readonly) NSString *subtitle;
@property (nonatomic, unsafe_unretained) MKPinAnnotationColor pinColor;// 气泡的颜色
// 初始化坐标(Coordinate)
- (id) initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates title:(NSString *)paramTitle subTitle:(NSString *)paramSubTitle;
@end
*.m 文件
#import "MyAnnotation.h"
@implementation MyAnnotation
@synthesize coordinate;
@synthesize title;
@synthesize subtitle;
@synthesize pinColor;
- (id) initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates title:(NSString *)paramTitle subTitle:(NSString *)paramSubTitle{
self = [super init];
if (self != nil){
coordinate = paramCoordinates;
title = paramTitle;
subtitle = paramSubTitle;
pinColor = MKPinAnnotationColorGreen;// 定义默认颜色
}
return(self);
}
@end
这样,我们就能够调用我们自定义的锚点类来进行锚点的添加!
贴:
#pragma mark - CLLocationManagerDelegate 定位服务
// 当获得了新的位置时,调用该方法
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(@"Latitude = %f", newLocation.coordinate.latitude);
NSLog(@"Longitude = %f", newLocation.coordinate.longitude);
// 定义一个2D坐标
CLLocationCoordinate2D location =CLLocationCoordinate2DMake(newLocation.coordinate.latitude,newLocation.coordinate.longitude);
// 初始化锚点,根据坐标,标题,副标题
MyAnnotation *annotation =[[MyAnnotation alloc] initWithCoordinates:location
title:@"My Title"
subTitle:@"My Sub Title"];
// 为地图增加锚点
[self.myMapView addAnnotation:annotation];
}
// 当无法获得位置时,调用该方法
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(@"无法获取经纬度!");
}
#pragma mark - MKMapViewDelegate
// 当地图界面将要加载的时候会调用该方法
- (void)mapViewWillStartLoadingMap:(MKMapView *)mapView{
NSLog(@"mapViewWillStartLoadingMap");
}
三、为地图定义不同颜色的锚点
原来,我也觉的挺复杂的。或者是什么其他的特殊方式。
但是,实际用了,感觉原理跟TableView中的返回Cell的代理方法:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
是一个尿性的!对,原理一样啊!
也就是实现MKMapViewDelegate协议的mapView方法:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
多的所以也不解释了!
贴:
// 返回锚点(大头针)的View,根据坐标信息
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation{
MKAnnotationView *result = nil;
if ([annotation isKindOfClass:[MyAnnotation class]] == NO){
return result;
}
if ([mapView isEqual:self.myMapView] == NO){
return result;
}
MyAnnotation *senderAnnotation = (MyAnnotation *)annotation;
// 获得锚点视图的颜色标识符
// 重用MKPinAnnotationView(跟重用TableView的Cell一个道理)
NSString *pinReusableIdentifier = @"myAnnotation";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:pinReusableIdentifier];
if (annotationView == nil){
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:senderAnnotation reuseIdentifier:pinReusableIdentifier];
[annotationView setCanShowCallout:YES];
}
annotationView.pinColor = senderAnnotation.pinColor;
result = annotationView;
return result;
}
四、通过地理坐标(经纬度)得到地址信息
当我们得到了一组经纬度数据,并且想把这组数据解析出来得到一个实在的地理位置名称。
通过一组经纬度数据得到一个实在的地理位置数据,我们通常称之为逆向地理编码。
我们使用CLGeocoder类可以来完成这项任务!
贴:
#pragma mark - CLLocationManagerDelegate 定位服务
// 当获得了新的位置时,调用该方法
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(@"Latitude = %f", newLocation.coordinate.latitude);
NSLog(@"Longitude = %f", newLocation.coordinate.longitude);
// 创建一个定位对象
CLLocation *thelocation = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude
longitude:newLocation.coordinate.longitude];
// 初始化一个反向地理编码对象
self.myGeocoder = [[CLGeocoder alloc] init];
// 根据给定的经纬度来得到相应的地址信息
[self.myGeocoder reverseGeocodeLocation:thelocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil && [placemarks count] > 0){
// CLPlacemark 存储着相应的地址数据
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(@"Country = %@", placemark.country);
NSLog(@"Postal Code = %@", placemark.postalCode);
NSLog(@"Locality = %@", placemark.locality);
}
else if (error == nil && [placemarks count] == 0){
NSLog(@"No results were returned.");
}
else if (error != nil){
NSLog(@"An error occurred = %@", error); }
}];
}
有几点需要说明mark一下:
CLLocation:标识一个物理坐标对象。可以存储经纬度、海拔等信息。
CLGeocoder:这是一个提供物理地址(经纬度)到真实地址的转换的服务。换算出来的信息一般包括:国家、城市、州、街道等信息。而且,这个类需要基于联网状态下才能工作。因为数据都存储在苹果的数据库中。你懂的。
- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler 方法:
用来转换地理坐标到真实地址的方法。
location:要转换的地址坐标
completionHandler:一个Block,请求返回时调用
在看一下CLGeocodeCompletionHandler这个Block的方法签名。
typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);
placemarks:返回查询的地理信息
error:是否成功
五、通过地址信息得到地理坐标(经纬度)
当然,我们应该想到,地理坐标与地址信息之间应该能够互相转化。
反向地理编码是通过一组经纬度数据的到一个实在的地理位置名称。同样我们可以使用地理编码通过一个地理名称得到一组经纬度数据。
CLGeocoder类可以来完成这项任务!
NSString *oreillyAddress =@"1005 Gravenstein Highway North, Sebastopol, CA 95472, USA";
self.myGeocoder = [[CLGeocoder alloc] init];
[self.myGeocoder geocodeAddressString:oreillyAddress completionHandler:^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > 0 && error == nil){
NSLog(@"Found %lu placemark(s).", (unsigned long)[placemarks count]);
CLPlacemark *firstPlacemark = [placemarks objectAtIndex:0];
NSLog(@"Longitude = %f", firstPlacemark.location.coordinate.longitude);
NSLog(@"Latitude = %f", firstPlacemark.location.coordinate.latitude);
}
else if ([placemarks count] == 0 &&
error == nil){
NSLog(@"Found no placemarks.");
}
else if (error != nil){
NSLog(@"An error occurred = %@", error);
}
}];
文章转载自: http://blog.sina.com.cn/s/blog_7b9d64af0101cays.html