CoreLocation框架ios
MapKit框架git
CoreLocation:用於地理定位,地理編碼區域監聽等(着重功能實現)
MapKit:用於地圖展現,例如大頭針,路線,覆蓋層展現等(着重界面展現)
複製代碼
CoreLocation框架中使用CLLocationManager對象來作用戶定位 建立(初始化)api
CLLocationManager *lM = [[CLLocationManager alloc] init];
複製代碼
每隔多少米定位一次數組
@property(assign, nonatomic) CLLocationDistance distanceFilter;
複製代碼
定位精確度(越精確就越耗電)bash
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
複製代碼
朝向改變時,每隔多少度調用一次app
@property(assign, nonatomic) CLLocationDegrees headingFilter
複製代碼
每隔多米定位一次框架
_lM.distanceFilter = 100;
/**
kCLLocationAccuracyBestForNavigation // 最適合導航
kCLLocationAccuracyBest; // 最好的
kCLLocationAccuracyNearestTenMeters; // 10m
kCLLocationAccuracyHundredMeters; // 100m
kCLLocationAccuracyKilometer; // 1000m
kCLLocationAccuracyThreeKilometers; // 3000m
*/
// 精確度越高, 越耗電, 定位時間越長
_lM.desiredAccuracy = kCLLocationAccuracyBest;
複製代碼
- (void)startUpdatingLocation;
複製代碼
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
複製代碼
locations參數裏面裝着CLLocation對象ide
- (void) stopUpdatingLocation;
複製代碼
判判定位功能是否可用(爲了嚴謹起見,最好在使用定位功能前進行判斷)ui
+ (BOOL)locationServicesEnabled;
複製代碼
監聽設備朝向編碼
-(void)startUpdatingHeading(如試例代碼中的指南針的實現)
複製代碼
區域監聽(監聽進出某個區域)
-(void)requestStateForRegion:region;
複製代碼
//使用位置管理者,開始更新用戶位置
// 默認只能在前臺獲取用戶位置,
// 勾選後臺模式 location updates
[self.lM startUpdatingLocation];
複製代碼
//監聽設備朝向
[self.lM startUpdatingHeading];
複製代碼
- 區域監聽(監聽進出某個區域)
[self.lM requestStateForRegion:region];
複製代碼
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
複製代碼
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
複製代碼
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
複製代碼
區域監聽的代理方法
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
複製代碼
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
複製代碼
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state
複製代碼
/**
* 更新到位置以後調用
*
* @param manager 位置管理者
* @param locations 位置數組
*/
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(@"定位到了");
// 拿到位置,作一些業務邏輯操做
// 中止更新
// [manager stopUpdatingLocation];
}
複製代碼
/**
* 受權狀態發生改變時調用
*
* @param manager 位置管理者
* @param status 狀態
*/
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
// 用戶還未決定
case kCLAuthorizationStatusNotDetermined:
{
NSLog(@"用戶還未決定");
break;
}
// 問受限
case kCLAuthorizationStatusRestricted:
{
NSLog(@"訪問受限");
break;
}
// 定位關閉時和對此APP受權爲never時調用
case kCLAuthorizationStatusDenied:
{
// 定位是否可用(是否支持定位或者定位是否開啓)
if([CLLocationManager locationServicesEnabled])
{
NSLog(@"定位開啓,但被拒");
}else
{
NSLog(@"定位關閉,不可用");
}
// NSLog(@"被拒");
break;
}
// 獲取先後臺定位受權
case kCLAuthorizationStatusAuthorizedAlways:
// case kCLAuthorizationStatusAuthorized: // 失效,不建議使用
{
NSLog(@"獲取先後臺定位受權");
break;
}
// 得到前臺定位受權
case kCLAuthorizationStatusAuthorizedWhenInUse:
{
NSLog(@"得到前臺定位受權");
break;
}
default:
break;
}
}
複製代碼
/**
* 簡易指南針的實現
* 手機朝向改變時調用
*
* @param manager 位置管理者
* @param newHeading 朝向對象
*/
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
/**
* CLHeading
* magneticHeading : 磁北角度
* trueHeading : 真北角度
*/
NSLog(@"%f", newHeading.magneticHeading);
CGFloat angle = newHeading.magneticHeading;
// 把角度轉弧度
CGFloat angleR = angle / 180.0 * M_PI;
// 旋轉圖片(指南針圖片)
[UIView animateWithDuration:0.25 animations:^{
self.compassView.transform = CGAffineTransformMakeRotation(-angleR);
}];
}
複製代碼
//區域監聽的代理方法
// 進入區域
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(@"進入區域--%@", region.identifier);
}
// 離開區域
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(@"離開區域--%@", region.identifier);
}
//監聽是否在某個區域的狀態
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
//state的值
//CLRegionStateUnknown,
//CLRegionStateInside,
//CLRegionStateOutside
NSLog(@"%zd", state);
}
複製代碼
CLLocation用來表示某個位置的地理信息,好比經緯度,海拔等等
經常使用屬性
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;
複製代碼
@property(readonly, nonatomic) CLLocationDistance altitude;
複製代碼
@property(readonly, nonatomic) CLLocationDirection course;
複製代碼
@property(readonly, nonatomic) CLLocationSpeed speed;
複製代碼
經常使用方法
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
複製代碼
/**
* CLLocationManager對象的代理方法,當用戶位置改變的時候調用
* 更新到位置以後調用
*
* @param manager 位置管理者
* @param locations 位置數組
* is kind of
*/
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
// NSLog(@"定位到了");
/**
* CLLocation 詳解
* coordinate : 經緯度
* altitude : 海拔
* course : 航向
* speed ; 速度
*/
CLLocation *location = [locations lastObject];
// NSLog(@"%@", location);
/**
* 場景演示:打印當前用戶的行走方向,偏離角度以及對應的行走距離,
例如:」北偏東 30度 方向,移動了8米」
*/
// 1. 獲取方向偏向
NSString *angleStr = nil;
switch ((int)location.course / 90) {
case 0:
angleStr = @"北偏東";
break;
case 1:
angleStr = @"東偏南";
break;
case 2:
angleStr = @"南偏西";
break;
case 3:
angleStr = @"西偏北";
break;
default:
angleStr = @"跑溝裏去了!!";
break;
}
// 2. 偏向角度
NSInteger angle = 0;
angle = (int)location.course % 90;
// 表明正方向
if (angle == 0) {
NSRange range = NSMakeRange(0, 1);
angleStr = [NSString stringWithFormat:@"正%@", [angleStr substringWithRange:range]];
}
// 3.移動多少米
double distance = 0;
if(_oldL)
{
distance = [location distanceFromLocation:_oldL];
}
_oldL = location;
// 4. 拼串 打印
// 例如:」北偏東 30度 方向,移動了8米」
NSString *noticeStr = [NSString stringWithFormat:@"%@%zd方向, 移動了%f米", angleStr, angle, distance];
NSLog(@"%@", noticeStr);
}
複製代碼
從ios8.0開始,蘋果進一步增強了對用戶隱私的保護。
當app想訪問用戶的隱私時,系統再也不自動彈出一個對話框讓用戶受權.
(1)調用ios8.0的api。主動請求用戶受權
(2)務必在info.plist文件中配置對應的鍵值, 不然以上請求受權的方法不生效
ios9.0若是當前處於前臺受權狀態,默認是不能夠後臺獲取用戶位置。但能夠設置如下屬性爲YES,就能夠繼續在後臺獲取位置,可是在屏幕上方會出現藍條
ios9.0能夠單次請求用戶位置
使用CLGeocoder能夠完成「地理編碼」和「反地理編碼」
對應方法
-(void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
複製代碼
-(void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
複製代碼
CLGeocodeCompletionHandler:反地理編碼完成時,就會調用CLGeocodeCompletionHandler
typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);
// 地理編碼
- (IBAction)geoCoder {
//當傳入的值爲0時直接返回
if ([self.addressDetailTV.text length] == 0) {
return;
}
// 地理編碼方案一:直接根據地址進行地理編碼(返回結果可能有多個,由於一個地點有重名)
[self.geoC geocodeAddressString:self.addressDetailTV.text completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) {
// 包含區,街道等信息的地標對象
CLPlacemark *placemark = [placemarks firstObject];
// 城市名稱
// NSString *city = placemark.locality;
// 街道名稱
// NSString *street = placemark.thoroughfare;
// 全稱
NSString *name = placemark.name;
self.addressDetailTV.text = [NSString stringWithFormat:@"%@", name];
self.latitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.latitude];
self.longtitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.longitude];
}];
// 地理編碼方案二:根據地址和區域兩個條件進行地理編碼(更加精確)
// [self.geoC geocodeAddressString:self.addressDetailTV.text inRegion:nil completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) {
// // 包含區,街道等信息的地標對象
// CLPlacemark *placemark = [placemarks firstObject];
// self.addressDetailTV.text = placemark.description;
// self.latitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.latitude];
// self.longtitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.longitude];
// }];
// 地理編碼方案三:
// NSDictionary *addressDic = @{
// (__bridge NSString *)kABPersonAddressCityKey : @"北京",
// (__bridge NSString *)kABPersonAddressStreetKey : @"棠下街"
// };
// [self.geoC geocodeAddressDictionary:addressDic completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) {
// CLPlacemark *placemark = [placemarks firstObject];
// self.addressDetailTV.text = placemark.description;
// self.latitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.latitude];
// self.longtitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.longitude];
// }];
}
複製代碼
// 反地理編碼
- (IBAction)decode {
// 過濾空數據
if ([self.latitudeTF.text length] == 0 || [self.longtitudeTF.text length] == 0) {
return;
}
// 建立CLLocation對象
CLLocation *location = [[CLLocation alloc] initWithLatitude:[self.latitudeTF.text doubleValue] longitude:[self.longtitudeTF.text doubleValue]];
// 根據CLLocation對象進行反地理編碼
[self.geoC reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) {
// 包含區,街道等信息的地標對象
CLPlacemark *placemark = [placemarks firstObject];
// 城市名稱
// NSString *city = placemark.locality;
// 街道名稱
// NSString *street = placemark.thoroughfare;
// 全稱
NSString *name = placemark.name;
self.addressDetailTV.text = [NSString stringWithFormat:@"%@", name];
}];
}
複製代碼
CLPlacemark的字面意思是地標,封裝詳細的地址位置信息 經常使用屬性
@property (nonatomic, readonly) CLLocation *location;
複製代碼
@property (nonatomic, readonly) CLRegion *region;
複製代碼
@property (nonatomic, readonly) NSDictionary *addressDictionary;
複製代碼
@property (nonatomic, readonly) NSString *name;
複製代碼
@property (nonatomic, readonly) NSString *locality;
複製代碼
經常使用屬性
地圖配型:mapType
操做項
顯示項
跟蹤顯示用戶的位置(ios8-地圖不會自動滾到用戶所在的位置,ios8+地圖會自動放大到合適比例,並顯示出用戶位置)
設置地圖顯示的區域和位置
設置地圖的中心點位置
設置地圖的顯示區域
typedef struct {
CLLocationCoordinate2D center; // 區域的中心點位置
MKCoordinateSpan span; // 區域的跨度
} MKCoordinateRegion;
複製代碼
typedef struct {
CLLocationDegrees latitudeDelta; // 緯度跨度
CLLocationDegrees longitudeDelta; // 經度跨度
} MKCoordinateSpan;
複製代碼
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
添加大頭針
移除大頭針
#import <MapKit/MapKit.h>
@interface TestAnnotation : NSObject <MKAnnotation>
/** 座標位置 */
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
/** 標題 */
@property (nonatomic, copy) NSString *title;
/** 子標題 */
@property (nonatomic, copy) NSString *subtitle;
@end
複製代碼
設置MKMapView代理
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// 判斷annotation的類型
if (![annotation isKindOfClass:[TestAnnotation class]]) return nil;
// 建立MKAnnotationView
static NSString *ID = @"tuangou";
MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID];
if (annoView == nil) {
annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID];
annoView.canShowCallout = YES;
}
複製代碼
地圖上的大頭針控件是MKAnnotationView
屬性
MKPinAnnotationView是MKAnnotationView的子類
MKPinAnnotationView比MKAnnotationView多了2個屬性
// 根據兩個地標對象進行調用系統導航
- (void)beginNavWithBeginPlacemark:(CLPlacemark *)beginPlacemark andEndPlacemark:(CLPlacemark *)endPlacemark
{
// 建立起點:根據 CLPlacemark 地標對象建立 MKPlacemark 地標對象
MKPlacemark *itemP1 = [[MKPlacemark alloc] initWithPlacemark:beginPlacemark];
MKMapItem *item1 = [[MKMapItem alloc] initWithPlacemark:itemP1];
// 建立終點:根據 CLPlacemark 地標對象建立 MKPlacemark 地標對象
MKPlacemark *itemP2 = [[MKPlacemark alloc] initWithPlacemark:endPlacemark];
MKMapItem *item2 = [[MKMapItem alloc] initWithPlacemark:itemP2];
NSDictionary *launchDic = @{
// 設置導航模式參數
MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,
// 設置地圖類型
MKLaunchOptionsMapTypeKey : @(MKMapTypeHybridFlyover),
// 設置是否顯示交通
MKLaunchOptionsShowsTrafficKey : @(YES),
};
// 根據 MKMapItem 數組 和 啓動參數字典 來調用系統地圖進行導航
[MKMapItem openMapsWithItems:@[item1, item2] launchOptions:launchDic];
}
複製代碼
// 建立視角中心座標
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(23.132931, 113.375924);
// 建立3D視角
MKMapCamera *camera = [MKMapCamera cameraLookingAtCenterCoordinate:center fromEyeCoordinate:CLLocationCoordinate2DMake(center.latitude + 0.001, center.longitude + 0.001) eyeAltitude:1];
// 設置到地圖上顯示
self.mapView.camera = camera;
複製代碼
// 截圖附加選項
MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
// 設置截圖區域(在地圖上的區域,做用在地圖)
options.region = self.mapView.region;
// options.mapRect = self.mapView.visibleMapRect;
// 設置截圖後的圖片大小(做用在輸出圖像)
options.size = self.mapView.frame.size;
// 設置截圖後的圖片比例(默認是屏幕比例, 做用在輸出圖像)
options.scale = [[UIScreen mainScreen] scale];
MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler:^(MKMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
if (error) {
NSLog(@"截圖錯誤:%@",error.localizedDescription);
}else
{
// 設置屏幕上圖片顯示
self.snapshootImageView.image = snapshot.image;
// 將圖片保存到指定路徑(此處是桌面路徑,須要根據我的電腦不一樣進行修改)
NSData *data = UIImagePNGRepresentation(snapshot.image);
[data writeToFile:@"/Users/wangshunzi/Desktop/snap.png" atomically:YES];
}
}];
複製代碼