在iOS開(kāi)發(fā)中扛点,要想加入地圖的地位這兩大功能津辩,必須基于兩個(gè)框架進(jìn)行開(kāi)發(fā):Map Kit(用于地圖展示)渡处、Core Location(用于地理定位)
地圖定位
CoreLocation框架的使用
-
導(dǎo)入框架(iOS5之后不再需要)
導(dǎo)入CoreLocation框架 - 導(dǎo)入頭文件:#import<CoreLocation/CoreLocation.h>
- CoreLocation框架使用須知
- CoreLocation框架中所有數(shù)據(jù)類(lèi)型的前綴都是CL
- CoreLocation中使用CLLocationManager對(duì)象來(lái)做用戶(hù)定位
CLLocationManager
類(lèi)方法 | 說(shuō)明 |
---|---|
+ (BOOL)locationServicesEnabled; | 檢測(cè)整個(gè)iOS系統(tǒng)的位置服務(wù)是否開(kāi)啟,即iPhone手機(jī)上的定位設(shè)置梦碗。通常如果用戶(hù)沒(méi)有啟用定位服務(wù)可以提示用戶(hù)打開(kāi)定位服務(wù) |
+ (CLAuthorizationStatus)authorizationStatus; | 指當(dāng)前應(yīng)用的定位服務(wù)授權(quán)狀態(tài),返回枚舉類(lèi)型:kCLAuthorizationStatusNotDetermined: 用戶(hù)尚未做出決定是否啟用定位服務(wù)kCLAuthorizationStatusRestricted: 沒(méi)有獲得用戶(hù)授權(quán)使用定位服務(wù),可能用戶(hù)沒(méi)有自己禁止訪問(wèn)授權(quán)kCLAuthorizationStatusDenied :用戶(hù)已經(jīng)明確禁止應(yīng)用使用定位服務(wù)或者當(dāng)前系統(tǒng)定位服務(wù)處于關(guān)閉狀態(tài)kCLAuthorizationStatusAuthorizedAlways: 應(yīng)用獲得授權(quán)可以一直使用定位服務(wù)蓖救,即使應(yīng)用不在使用狀態(tài)kCLAuthorizationStatusAuthorizedWhenInUse: 使用此應(yīng)用過(guò)程中允許訪問(wèn)定位服務(wù) |
屬性 | 說(shuō)明 |
desiredAccuracy | 定位精度(越精確越耗電)洪规,枚舉類(lèi)型:kCLLocationAccuracyBest:最精確定位CLLocationAccuracy kCLLocationAccuracyNearestTenMeters:十米誤差范圍kCLLocationAccuracyHundredMeters:百米誤差范圍kCLLocationAccuracyKilometer:千米誤差范圍kCLLocationAccuracyThreeKilometers:三千米誤差范圍 |
distanceFilter | 位置信息更新最小距離,只有移動(dòng)大于這個(gè)距離才更新位置信息循捺,默認(rèn)為kCLDistanceFilterNone:不進(jìn)行距離限制 |
對(duì)象方法 | 說(shuō)明 |
startUpdatingLocation | 開(kāi)始定位追蹤斩例,開(kāi)始定位后將按照用戶(hù)設(shè)置的更新頻率b不斷地定位用戶(hù)的位置,頻繁地執(zhí)行**-(void)locationManager:(CLLocationManager )manager didUpdateLocations:(NSArray )locations方法來(lái)反饋定位信息从橘,參數(shù)locations是一個(gè)數(shù)組念赶,里面的元素對(duì)象是CLLocation對(duì)象 |
stopUpdatingLocation | 停止定位追蹤 |
startUpdatingHeading | 開(kāi)始導(dǎo)航方向追蹤 |
stopUpdatingHeading | 停止導(dǎo)航方向追蹤 |
startMonitoringForRegion: | 開(kāi)始對(duì)某個(gè)區(qū)域進(jìn)行定位追蹤。如果用戶(hù)進(jìn)入或者走出某個(gè)區(qū)域會(huì)調(diào)用- (void)locationManager:(CLLocationManager )manager didEnterRegion:(CLRegion )region和- (void)locationManager:(CLLocationManager )manager didExitRegion:(CLRegion )region代理方法反饋相關(guān)信息 |
stopMonitoringForRegion: | 停止對(duì)某個(gè)區(qū)域進(jìn)行定位追蹤 |
requestWhenInUseAuthorization | 請(qǐng)求獲得應(yīng)用使用時(shí)的定位服務(wù)授權(quán)恰力,注意使用此方法前在要在info.plist中配置NSLocationWhenInUseUsageDescription |
requestAlwaysAuthorization | 請(qǐng)求獲得應(yīng)用一直使用定位服務(wù)授權(quán)叉谜,注意使用此方法前要在info.plist中配置NSLocationAlwaysUsageDescription |
代理方法 | 說(shuō)明 |
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations; | 位置發(fā)生改變后執(zhí)行(第一次定位到某個(gè)位置之后也會(huì)執(zhí)行) |
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading; | 導(dǎo)航方向發(fā)生變化后執(zhí)行 |
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region | 進(jìn)入某個(gè)區(qū)域之后執(zhí)行 |
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region | 走出某個(gè)區(qū)域之后執(zhí)行 |
#import "ForthViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface ForthViewController ()<CLLocationManagerDelegate>
// 聲明位置管理器屬性
@property (nonatomic, strong) CLLocationManager *locationManager;
@end
@implementation ForthViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [CLLocationManager new];
// [CLLocationManager locationServicesEnabled]這句話(huà)檢測(cè)的是整個(gè)iOS系統(tǒng)的位置服務(wù)是否開(kāi)啟,即iPhone手機(jī)上的定位設(shè)置踩萎。通常如果用戶(hù)沒(méi)有啟用定位服務(wù)可以提示用戶(hù)打開(kāi)定位服務(wù)
if (![CLLocationManager locationServicesEnabled])
{
NSLog(@"手機(jī)定位服務(wù)當(dāng)前可能尚未打開(kāi)停局,請(qǐng)?jiān)O(shè)置打開(kāi)");
return;
}
/*
[CLLocationManager authorizationStatus]指的是當(dāng)前應(yīng)用的定位服務(wù)授權(quán)狀態(tài),返回枚舉類(lèi)型
kCLAuthorizationStatusNotDetermined:用戶(hù)尚未做出決定是否啟用定位服務(wù)
kCLAuthorizationStatusRestricted:沒(méi)有獲得用戶(hù)授權(quán)使用定位服務(wù),可能用戶(hù)沒(méi)有自己禁止訪問(wèn)授權(quán)
kCLAuthorizationStatusDenied:用戶(hù)已經(jīng)明確禁止應(yīng)用使用定位服務(wù)或者當(dāng)前系統(tǒng)定位服務(wù)處于關(guān)閉狀態(tài)
kCLAuthorizationStatusAuthorizedAlways:應(yīng)用獲得授權(quán)可以一直使用定位服務(wù),即使應(yīng)用不在使用狀態(tài)
kCLAuthorizationStatusAuthorizedWhenInUse:使用此應(yīng)用過(guò)程中允許訪問(wèn)定位服務(wù)
*/
// 如果沒(méi)有授權(quán)則請(qǐng)求用戶(hù)授權(quán)
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
{
NSLog(@"請(qǐng)求用戶(hù)授權(quán)");
[self.locationManager requestWhenInUseAuthorization];
}
// 如果被授權(quán)
else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse)
{
// 設(shè)置代理
self.locationManager.delegate = self;
/*
kCLLocationAccuracyBest:最精確的董栽,也是最耗電的码倦,越精確越耗電
kCLLocationAccuracyNearestTenMeters:十米誤差范圍
kCLLocationAccuracyHundredMeters:百米誤差范圍
kCLLocationAccuracyKilometer:千米誤差范圍
kCLLocationAccuracyThreeKilometers:三千米
*/
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// 定位頻率(每隔多少米定位一次,單位是米)
// CLLocationDistance distance = 10.0;// 每隔十米定位一次
// self.locationManager.distanceFilter = distance;
// 定位頻率設(shè)置為kCLDistanceFilterNone的話(huà)锭碳,會(huì)不停地定位袁稽,只有幾秒的延時(shí)
self.locationManager.distanceFilter = kCLDistanceFilterNone;
// 開(kāi)始定位
[self.locationManager startUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
// 取出位置
CLLocation *location = [locations firstObject];
// 位置坐標(biāo)
CLLocationCoordinate2D coordinate = location.coordinate;
NSLog(@"經(jīng)度:%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可以完成地理編碼和反地理編碼
- 地理編碼:根據(jù)給定的地名,獲得具體的位置信息(比如經(jīng)緯度擒抛、地址的全稱(chēng)等)
- 反地理編碼:根據(jù)給定的經(jīng)緯度运提,獲得具體的位置信息
地理編碼方法:- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
反地理編碼方法:- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
// 地理編碼、反地理編碼
// 地理編碼:根據(jù)給定的位置(通常是地名)闻葵,確定地理坐標(biāo)(經(jīng)緯度)
// 反地理編碼:根據(jù)給定地理坐標(biāo)(經(jīng)緯度)民泵,確定位置信息(街道、門(mén)牌等等)
#import "SecondViewController.h"
// 引入定位頭文件
#import <CoreLocation/CoreLocation.h>
@interface SecondViewController ()
// 聲明編碼屬性
@property (nonatomic, strong) CLGeocoder *geocoder;
@end
@implementation SecondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 初始化編碼對(duì)象
self.geocoder = [CLGeocoder new];
// [self getCoordinateByAddress:@"北京市海淀區(qū)清河"];
[self getAddressByLatitude:40.0305627852 longitude:116.3435577061];
}
#pragma mark ------------------ 地理編碼 --------------------
- (void)getCoordinateByAddress:(NSString *)address
{
[self.geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error)
{
// 獲取第一個(gè)地標(biāo)槽畔,地標(biāo)中存儲(chǔ)了詳細(xì)的地址信息栈妆。注意:一個(gè)地名可能搜索出多個(gè)地址
CLPlacemark *placeMark = [placemarks firstObject];
// 獲取位置
CLLocation *location = placeMark.location;
// 獲取區(qū)域
CLRegion *region = placeMark.region;
// 詳細(xì)信息
NSDictionary *dic = placeMark.addressDictionary;
// 地名
NSString *name = [NSString stringWithString:[placeMark.name stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
// 街道
NSString *thoroughFare = placeMark.thoroughfare;
// 街道相關(guān)信息
NSString *subThoroughfare = placeMark.subThoroughfare;
// 城市
NSString *locality = placeMark.locality;
// 州
NSString *administrativeArea = placeMark.administrativeArea;
// 其他行政區(qū)域信息
NSString *subAdministrativeArea = placeMark.subAdministrativeArea;
// 郵編
NSString *postalCode = placeMark.postalCode;
// 國(guó)家編碼
NSString *ISOcountryCode = placeMark.ISOcountryCode;
// 國(guó)家
NSString *country = placeMark.country;
// 水源、湖泊
NSString *inlandWater = placeMark.inlandWater;
// 海洋
NSString *ocean = placeMark.ocean;
// 關(guān)聯(lián)或者利益相關(guān)的地標(biāo)
NSArray *areasOfInterest = placeMark.areasOfInterest;
NSLog(@"\n位置:%@\n區(qū)域:%@\n詳細(xì)信息:%@\n名字:%@\n街道:%@\n街道相關(guān)信息:%@\n城市:%@\n州:%@\n其他行政區(qū)域信息:%@\n郵編:%@\n國(guó)家編碼:%@\n國(guó)家:%@\n水源厢钧、湖泊:%@\n海洋:%@\n關(guān)聯(lián)或者利益相關(guān)的地標(biāo):%@\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<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error)
{
CLPlacemark *placeMark = [placemarks firstObject];
NSLog(@"詳細(xì)信息:%@", placeMark.addressDictionary);
NSLog(@"地名:%@", [NSString stringWithString:[placeMark.addressDictionary[@"Name"] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]);
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
地理編碼和反地理編碼方法中也可以調(diào)用系統(tǒng)自帶的地圖定位(需要展示地圖的話(huà)鳞尔,首先得導(dǎo)入MapKit框架,即引入頭文件#import <MapKit/MapKit.h>)
// 通過(guò)地理編碼調(diào)用系統(tǒng)地圖定位
#import "ThirdViewController.h"
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
@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 ------------- 確定一個(gè)城市的位置 --------------
- (void)location_1
{
[self.geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error)
{
// 獲取第一個(gè)地標(biāo)
CLPlacemark *clplaceMark = [placemarks firstObject];
// 將定位地標(biāo)轉(zhuǎn)換為地圖地標(biāo)
MKPlacemark *mkplaceMark = [[MKPlacemark alloc] initWithPlacemark:clplaceMark];
// 字典中放一個(gè)地圖類(lèi)型
NSDictionary *options = @{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};
// 初始化地圖組
MKMapItem *maoItem = [[MKMapItem alloc] initWithPlacemark:mkplaceMark];
// 打開(kāi)地圖早直,根據(jù)地圖類(lèi)型
[maoItem openInMapsWithLaunchOptions:options];
}];
}
#pragma mark -------------- 確定兩個(gè)城市的位置 -------------
- (void)location_2
{
[self.geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error)
{
// 獲取第一個(gè)地標(biāo)
CLPlacemark *CLplaceMarkBJ = [placemarks firstObject];
// 將定位地標(biāo)轉(zhuǎn)換為地圖地標(biāo)
MKPlacemark *MKplaceMarkBJ = [[MKPlacemark alloc] initWithPlacemark:CLplaceMarkBJ];
// 注意:地理編碼一個(gè)只能定位一個(gè)城市寥假,不能同時(shí)定位,想要再次定位需要將第二個(gè)地理編碼方法放到第一個(gè)地理編碼方法的回調(diào)函數(shù)中進(jìn)行第二個(gè)城市的定位
[self.geocoder geocodeAddressString:@"石家莊" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error)
{
// 獲取第一個(gè)地標(biāo)
CLPlacemark *CLplaceMarkSJZ = [placemarks firstObject];
// 將定位地標(biāo)轉(zhuǎn)換為地圖地標(biāo)
MKPlacemark *MKplaceMarkSJZ = [[MKPlacemark alloc] initWithPlacemark:CLplaceMarkSJZ];
// 字典中放一個(gè)地圖類(lèi)型
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框架的使用
- 導(dǎo)入框架(iOS5之后不再需要程序員導(dǎo)入)
導(dǎo)入MapKit框架
- 導(dǎo)入頭文件 #import <MapKit/MapKit.h>
- MapKit框架使用須知
- MapKit框架中所有數(shù)據(jù)類(lèi)型的前綴都是MK
- MapKit有一個(gè)比較重要的UI控件:MKMapView霞扬,專(zhuān)門(mén)用于地圖顯示糕韧,下表總結(jié)了一些MKMapView常用的屬性和方法
屬性 | 說(shuō)明 |
---|---|
zoomEnabled | 觸摸縮放(默認(rèn)可縮放) |
scrollEnabled | 移動(dòng)(默認(rèn)可移動(dòng)) |
mapType | 地圖類(lèi)型,是一個(gè)枚舉:MKMapTypeStandard :標(biāo)準(zhǔn)地圖喻圃,一般情況下使用此地圖即可滿(mǎn)足萤彩;MKMapTypeSatellite :衛(wèi)星地圖;MKMapTypeHybrid :混合地圖斧拍,加載最慢比較消耗資源雀扶; |
userTrackingMode | 跟蹤類(lèi)型,是一個(gè)枚舉:MKUserTrackingModeNone :不進(jìn)行用戶(hù)位置跟蹤肆汹;MKUserTrackingModeFollow :跟蹤用戶(hù)位置愚墓;MKUserTrackingModeFollowWithHeading :跟蹤用戶(hù)位置并且跟蹤用戶(hù)前進(jìn)方向; |
userLocation | 用戶(hù)位置昂勉,只讀屬性 |
annotations | 當(dāng)前地圖中的所有大頭針浪册,只讀屬性 |
對(duì)象方法 | 說(shuō)明 |
- (void)addAnnotation:(id <MKAnnotation>)annotation; | 添加大頭針,對(duì)應(yīng)的有添加大頭針數(shù)組 |
- (void)removeAnnotation:(id <MKAnnotation>)annotation; | 刪除大頭針硼啤,對(duì)應(yīng)的有刪除大頭針數(shù)組 |
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated; | 設(shè)置地圖顯示區(qū)域议经,用于控制當(dāng)前屏幕顯示地圖范圍 |
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated; | 設(shè)置地圖中心點(diǎn)位置 |
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view; | 將地理坐標(biāo)(經(jīng)緯度)轉(zhuǎn)化為數(shù)學(xué)坐標(biāo)(UIKit坐標(biāo)) |
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view; | 將數(shù)學(xué)坐標(biāo)轉(zhuǎn)換為地理坐標(biāo) |
- (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier; | 從緩存池中取出大頭針斧账,類(lèi)似于UITableView中取出UITableViewCell,為了進(jìn)行性能優(yōu)化而設(shè)計(jì) |
- (void)selectAnnotation:(id <MKAnnotation>)annotation animated:(BOOL)animated; | 選中指定的大頭針 |
- (void)deselectAnnotation:(id <MKAnnotation>)annotation animated:(BOOL)animated; | 取消選中指定的大頭針 |
代理方法 | 說(shuō)明 |
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation ; | 用戶(hù)位置發(fā)生改變時(shí)觸發(fā)(第一次定位到用戶(hù)位置也會(huì)觸發(fā)該方法) |
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation ; | 顯示區(qū)域發(fā)生改變后觸發(fā) |
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView; | 地圖加載完成后觸發(fā) |
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation; | 顯示大頭針時(shí)觸發(fā)煞肾,返回大頭針視圖咧织,通常自定義大頭針可以通過(guò)此方法進(jìn)行 |
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view; | 點(diǎn)擊選中某個(gè)大頭針時(shí)觸發(fā) |
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view; | 取消選中大頭針時(shí)觸發(fā) |
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay; | 渲染地圖覆蓋物時(shí)觸發(fā) |