在iOS开发中,要想加入地图的地位这两大功能,必须基于两个框架进行开发:Map Kit(用于地图展示)、Core Location(用于地理定位)
地图定位
CoreLocation框架的使用
-
导入框架(iOS5之后不再需要)
- 导入头文件:#import
- CoreLocation框架使用须知
- CoreLocation框架中所有数据类型的前缀都是CL
- CoreLocation中使用CLLocationManager对象来做用户定位
CLLocationManager
类方法 | 说明 |
---|---|
+ (BOOL)locationServicesEnabled; | 检测整个iOS系统的位置服务是否开启,即iPhone手机上的定位设置。通常如果用户没有启用定位服务可以提示用户打开定位服务 |
+ (CLAuthorizationStatus)authorizationStatus; | 指当前应用的定位服务授权状态,返回枚举类型:kCLAuthorizationStatusNotDetermined: 用户尚未做出决定是否启用定位服务kCLAuthorizationStatusRestricted: 没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权kCLAuthorizationStatusDenied :用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态kCLAuthorizationStatusAuthorizedAlways: 应用获得授权可以一直使用定位服务,即使应用不在使用状态kCLAuthorizationStatusAuthorizedWhenInUse: 使用此应用过程中允许访问定位服务 |
属性 | 说明 |
desiredAccuracy | 定位精度(越精确越耗电),枚举类型:kCLLocationAccuracyBest:最精确定位CLLocationAccuracy kCLLocationAccuracyNearestTenMeters:十米误差范围kCLLocationAccuracyHundredMeters:百米误差范围kCLLocationAccuracyKilometer:千米误差范围kCLLocationAccuracyThreeKilometers:三千米误差范围 |
distanceFilter | 位置信息更新最小距离,只有移动大于这个距离才更新位置信息,默认为kCLDistanceFilterNone:不进行距离限制 |
对象方法 | 说明 |
startUpdatingLocation | 开始定位追踪,开始定位后将按照用户设置的更新频率b不断地定位用户的位置,频繁地执行**-(void)locationManager:(CLLocationManager )manager didUpdateLocations:(NSArray )locations方法来反馈定位信息,参数locations是一个数组,里面的元素对象是CLLocation对象 |
stopUpdatingLocation | 停止定位追踪 |
startUpdatingHeading | 开始导航方向追踪 |
stopUpdatingHeading | 停止导航方向追踪 |
startMonitoringForRegion: | 开始对某个区域进行定位追踪。如果用户进入或者走出某个区域会调用- (void)locationManager:(CLLocationManager )manager didEnterRegion:(CLRegion )region和- (void)locationManager:(CLLocationManager )manager didExitRegion:(CLRegion )region代理方法反馈相关信息 |
stopMonitoringForRegion: | 停止对某个区域进行定位追踪 |
requestWhenInUseAuthorization | 请求获得应用使用时的定位服务授权,注意使用此方法前在要在info.plist中配置NSLocationWhenInUseUsageDescription |
requestAlwaysAuthorization | 请求获得应用一直使用定位服务授权,注意使用此方法前要在info.plist中配置NSLocationAlwaysUsageDescription |
代理方法 | 说明 |
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations; | 位置发生改变后执行(第一次定位到某个位置之后也会执行) |
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading; | 导航方向发生变化后执行 |
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region | 进入某个区域之后执行 |
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region | 走出某个区域之后执行 |
#import "ForthViewController.h"
#import
@interface ForthViewController ()
// 声明位置管理器属性
@property (nonatomic, strong) CLLocationManager *locationManager;
@end
@implementation ForthViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [CLLocationManager new];
// [CLLocationManager locationServicesEnabled]这句话检测的是整个iOS系统的位置服务是否开启,即iPhone手机上的定位设置。通常如果用户没有启用定位服务可以提示用户打开定位服务
if (![CLLocationManager locationServicesEnabled])
{
NSLog(@"手机定位服务当前可能尚未打开,请设置打开");
return;
}
/*
[CLLocationManager authorizationStatus]指的是当前应用的定位服务授权状态,返回枚举类型
kCLAuthorizationStatusNotDetermined:用户尚未做出决定是否启用定位服务
kCLAuthorizationStatusRestricted:没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权
kCLAuthorizationStatusDenied:用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态
kCLAuthorizationStatusAuthorizedAlways:应用获得授权可以一直使用定位服务,即使应用不在使用状态
kCLAuthorizationStatusAuthorizedWhenInUse:使用此应用过程中允许访问定位服务
*/
// 如果没有授权则请求用户授权
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
{
NSLog(@"请求用户授权");
[self.locationManager requestWhenInUseAuthorization];
}
// 如果被授权
else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse)
{
// 设置代理
self.locationManager.delegate = self;
/*
kCLLocationAccuracyBest:最精确的,也是最耗电的,越精确越耗电
kCLLocationAccuracyNearestTenMeters:十米误差范围
kCLLocationAccuracyHundredMeters:百米误差范围
kCLLocationAccuracyKilometer:千米误差范围
kCLLocationAccuracyThreeKilometers:三千米
*/
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// 定位频率(每隔多少米定位一次,单位是米)
// CLLocationDistance distance = 10.0;// 每隔十米定位一次
// self.locationManager.distanceFilter = distance;
// 定位频率设置为kCLDistanceFilterNone的话,会不停地定位,只有几秒的延时
self.locationManager.distanceFilter = kCLDistanceFilterNone;
// 开始定位
[self.locationManager startUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
// 取出位置
CLLocation *location = [locations firstObject];
// 位置坐标
CLLocationCoordinate2D coordinate = location.coordinate;
NSLog(@"经度:%f,纬度:%f,海拔:%f,航向:%f,行走速度:%f",coordinate.longitude,coordinate.latitude,location.altitude,location.course,location.speed);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
// 让模拟器演示定位
#ifdef TARGET_IPHONE_SIMULATOR
@interface CLLocationManager (Simulator)
-(void)startUpdatingLocation;
@end
@implementation CLLocationManager (Simulator)
-(void)startUpdatingLocation
{
float latitude = 32.061;
float longitude = 118.79125;
CLLocation *setLocation= [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
NSArray *array = [NSArray arrayWithObject:setLocation];
[self.delegate locationManager:self didUpdateLocations:array];}
@end
#endif // TARGET_IPHONE_SIMULATOR
地理编码和反编码
使用CLGeocoder可以完成地理编码和反地理编码
- 地理编码:根据给定的地名,获得具体的位置信息(比如经纬度、地址的全称等)
- 反地理编码:根据给定的经纬度,获得具体的位置信息
地理编码方法:- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
反地理编码方法:- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
// 地理编码、反地理编码
// 地理编码:根据给定的位置(通常是地名),确定地理坐标(经纬度)
// 反地理编码:根据给定地理坐标(经纬度),确定位置信息(街道、门牌等等)
#import "SecondViewController.h"
// 引入定位头文件
#import
@interface SecondViewController ()
// 声明编码属性
@property (nonatomic, strong) CLGeocoder *geocoder;
@end
@implementation SecondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 初始化编码对象
self.geocoder = [CLGeocoder new];
// [self getCoordinateByAddress:@"北京市海淀区清河"];
[self getAddressByLatitude:40.0305627852 longitude:116.3435577061];
}
#pragma mark ------------------ 地理编码 --------------------
- (void)getCoordinateByAddress:(NSString *)address
{
[self.geocoder geocodeAddressString:address completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error)
{
// 获取第一个地标,地标中存储了详细的地址信息。注意:一个地名可能搜索出多个地址
CLPlacemark *placeMark = [placemarks firstObject];
// 获取位置
CLLocation *location = placeMark.location;
// 获取区域
CLRegion *region = placeMark.region;
// 详细信息
NSDictionary *dic = placeMark.addressDictionary;
// 地名
NSString *name = [NSString stringWithString:[placeMark.name stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
// 街道
NSString *thoroughFare = placeMark.thoroughfare;
// 街道相关信息
NSString *subThoroughfare = placeMark.subThoroughfare;
// 城市
NSString *locality = placeMark.locality;
// 州
NSString *administrativeArea = placeMark.administrativeArea;
// 其他行政区域信息
NSString *subAdministrativeArea = placeMark.subAdministrativeArea;
// 邮编
NSString *postalCode = placeMark.postalCode;
// 国家编码
NSString *ISOcountryCode = placeMark.ISOcountryCode;
// 国家
NSString *country = placeMark.country;
// 水源、湖泊
NSString *inlandWater = placeMark.inlandWater;
// 海洋
NSString *ocean = placeMark.ocean;
// 关联或者利益相关的地标
NSArray *areasOfInterest = placeMark.areasOfInterest;
NSLog(@"\n位置:%@\n区域:%@\n详细信息:%@\n名字:%@\n街道:%@\n街道相关信息:%@\n城市:%@\n州:%@\n其他行政区域信息:%@\n邮编:%@\n国家编码:%@\n国家:%@\n水源、湖泊:%@\n海洋:%@\n关联或者利益相关的地标:%@\n", location, region, dic, name, thoroughFare, subThoroughfare, locality, administrativeArea, subAdministrativeArea, postalCode, ISOcountryCode, country, inlandWater, ocean, areasOfInterest);
}];
}
#pragma mark ----------------- 反地理编码 -----------------
- (void) getAddressByLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude
{
// 初始化位置信息
CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
// 反地理编码
[self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error)
{
CLPlacemark *placeMark = [placemarks firstObject];
NSLog(@"详细信息:%@", placeMark.addressDictionary);
NSLog(@"地名:%@", [NSString stringWithString:[placeMark.addressDictionary[@"Name"] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]);
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
地理编码和反地理编码方法中也可以调用系统自带的地图定位(需要展示地图的话,首先得导入MapKit框架,即引入头文件#import
// 通过地理编码调用系统地图定位
#import "ThirdViewController.h"
#import
#import
@interface ThirdViewController ()
@property (nonatomic, strong) CLGeocoder *geocoder;
@end
@implementation ThirdViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.geocoder = [CLGeocoder new];
// [self location_1];
[self location_2];
}
#pragma mark ------------- 确定一个城市的位置 --------------
- (void)location_1
{
[self.geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error)
{
// 获取第一个地标
CLPlacemark *clplaceMark = [placemarks firstObject];
// 将定位地标转换为地图地标
MKPlacemark *mkplaceMark = [[MKPlacemark alloc] initWithPlacemark:clplaceMark];
// 字典中放一个地图类型
NSDictionary *options = @{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};
// 初始化地图组
MKMapItem *maoItem = [[MKMapItem alloc] initWithPlacemark:mkplaceMark];
// 打开地图,根据地图类型
[maoItem openInMapsWithLaunchOptions:options];
}];
}
#pragma mark -------------- 确定两个城市的位置 -------------
- (void)location_2
{
[self.geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error)
{
// 获取第一个地标
CLPlacemark *CLplaceMarkBJ = [placemarks firstObject];
// 将定位地标转换为地图地标
MKPlacemark *MKplaceMarkBJ = [[MKPlacemark alloc] initWithPlacemark:CLplaceMarkBJ];
// 注意:地理编码一个只能定位一个城市,不能同时定位,想要再次定位需要将第二个地理编码方法放到第一个地理编码方法的回调函数中进行第二个城市的定位
[self.geocoder geocodeAddressString:@"石家庄" completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error)
{
// 获取第一个地标
CLPlacemark *CLplaceMarkSJZ = [placemarks firstObject];
// 将定位地标转换为地图地标
MKPlacemark *MKplaceMarkSJZ = [[MKPlacemark alloc] initWithPlacemark:CLplaceMarkSJZ];
// 字典中放一个地图类型
NSDictionary *Options = @{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};
MKMapItem *item1 = [[MKMapItem alloc] initWithPlacemark:MKplaceMarkBJ];
MKMapItem *item2 = [[MKMapItem alloc] initWithPlacemark:MKplaceMarkSJZ];
[MKMapItem openMapsWithItems:@[item1, item2] launchOptions:Options];
}];
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
地图显示
MapKit框架的使用
- 导入框架(iOS5之后不再需要程序员导入)
- 导入头文件 #import
- MapKit框架使用须知
- MapKit框架中所有数据类型的前缀都是MK
- MapKit有一个比较重要的UI控件:MKMapView,专门用于地图显示,下表总结了一些MKMapView常用的属性和方法
属性 | 说明 |
---|---|
zoomEnabled | 触摸缩放(默认可缩放) |
scrollEnabled | 移动(默认可移动) |
mapType | 地图类型,是一个枚举:MKMapTypeStandard :标准地图,一般情况下使用此地图即可满足;MKMapTypeSatellite :卫星地图;MKMapTypeHybrid :混合地图,加载最慢比较消耗资源; |
userTrackingMode | 跟踪类型,是一个枚举:MKUserTrackingModeNone :不进行用户位置跟踪;MKUserTrackingModeFollow :跟踪用户位置;MKUserTrackingModeFollowWithHeading :跟踪用户位置并且跟踪用户前进方向; |
userLocation | 用户位置,只读属性 |
annotations | 当前地图中的所有大头针,只读属性 |
对象方法 | 说明 |
- (void)addAnnotation:(id |
添加大头针,对应的有添加大头针数组 |
- (void)removeAnnotation:(id |
删除大头针,对应的有删除大头针数组 |
- (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 |
选中指定的大头针 |
- (void)deselectAnnotation:(id |
取消选中指定的大头针 |
代理方法 | 说明 |
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation ; | 用户位置发生改变时触发(第一次定位到用户位置也会触发该方法) |
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation ; | 显示区域发生改变后触发 |
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView; | 地图加载完成后触发 |
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id |
显示大头针时触发,返回大头针视图,通常自定义大头针可以通过此方法进行 |
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view; | 点击选中某个大头针时触发 |
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view; | 取消选中大头针时触发 |
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id |
渲染地图覆盖物时触发 |