核心定位和地图的相关功能-浅析

在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

你可能感兴趣的:(地图)