地圖與定位

 

專業術語  1. LBS :Location Based Serviceios

 

      2. SoLoMo :Social Local Mobile(索羅門)git

 

CLLocation用來表示某個位置的地理信息,好比經緯度、海拔等等數組

@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;經緯度app

@property(readonly, nonatomic) CLLocationDistance altitude;海拔框架

@property(readonly, nonatomic) CLLocationDirection course;路線,航向(取值範圍是0.0° ~ 359.9°,0.0°表明真北方向)函數

@property(readonly, nonatomic) CLLocationSpeed speed;行走速度(單位是m/s)性能

@property(assign, nonatomic) CLLocationDistance distanceFilter;每隔多少米定位一次測試

@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;定位精確度(越精確就越耗電)atom

 

CLLocationCoordinate2D是一個用來表示經緯度的結構體,通常用CLLocationCoordinate2DMake函數來建立CLLocationCoordinate2Dspa

typedef struct {

        CLLocationDegrees latitude; // 緯度

        CLLocationDegrees longitude; // 經度

} CLLocationCoordinate2D;

 

中國的經緯度範圍

緯度範圍:N 3°51′ ~  N 53°33′

經度範圍:E 73°33′ ~  E 135°05′

中國部分城市的經緯度

 

用- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location方法能夠計算2個位置之間的距離

1、獲取用戶的位置

一、在應⽤中使用CoreLocation,須要將框架 CoreLocation 加入項⺫標,而且根據須要導入Core Location 頭文件 

#import<CoreLocation/CoreLocation.h>   //用於地理定位

二、要在應用中使用MapKit,須要將框架MapKit加入項目標,並在所用它的類中導入MapKit頭文件 

#import<MapKit/MapKit.h>    //用於地圖展現

三、Core Location 尊重用戶隱私,僅在用戶許可時獲取設備的當前位置。在應用「設置」的「隱私」部 分,能夠關閉或開啓定位服務,還能夠禁止或容許特定應用獲取位置信息, 要請求用戶容許使⽤定位服務,應用須要讓CLLocationManager實例開始更新當前位置或將 MKMapView實例的屬性 ShowsUserLocation設置爲YES。若是設備關閉了定位服務,Core Location將提醒用戶在應用「設置」中開啓定位服務;若是Core Location之前未請求⽤戶容許獲取 設備的位置,它將顯示一個提示框,請求⽤戶許可。 

 //CoreLocation中使用CLLocationManager對象來作用戶定位

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
爲何在這裏CLLocationManager實例對象必須保存? 
在 iOS8 中須要專門做出申請,首先在info.plist中添加key
NSLocationWhenInUseUsageDescription 或者 NSLocationAlwaysUsageDescription 申請時給用戶的提示的文字信息做爲key的內容。 
 
 
在authorizationStatus狀態是 kCLAuthorizationStatusNotDetermined 時: 
    //受權狀態
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
        //申請受權
        [self.locationManager requestWhenInUseAuthorization];
    }

  //    kCLAuthorizationStatusNotDetermined = 0//用戶還沒有作出決定是否啓用定位服務

    //    kCLAuthorizationStatusRestricted//沒有得到用戶受權使用定位服務,可能用戶沒有本身禁止訪問受權

    //    kCLAuthorizationStatusDenied//用戶已經明確禁止應用使用定位服務或者當前系統定位服務處於關閉狀態

    //    kCLAuthorizationStatusAuthorizedAlways NS_ENUM_AVAILABLE(NA, 8_0)//應用得到受權能夠一直使用定位服務,即便應用不在使用狀態   

    //    kCLAuthorizationStatusAuthorizedWhenInUse NS_ENUM_AVAILABLE(NA, 8_0)//使用此應用過程當中容許訪問定位服務

    //    kCLAuthorizationStatusAuthorized NS_ENUM_DEPRECATED(10_6, NA, 2_0, 8_0, "Use kCLAuthorizationStatusAuthorizedAlways") = kCLAuthorizationStatusAuthorizedAlways//已經廢棄

四、檢查定位服務是否開啓

    //GPS硬件打開
    if (![CLLocationManager locationServicesEnabled]) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"GPS未開啓" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];
    }

五、請求數據

    //實例化
    self.locationManager = [[CLLocationManager alloc] init];

    //GPS精確度 kCLLocationAccuracyBestForNavigation 導航級別(Best 最精肯定位)(HundredMeters 百米級)(Kilometer 公里級)(ThreeKilometers 3公里級)
  [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    
    //設置距離過濾, 移動多少距離觸發新的位置事件
    [self.locationManager setDistanceFilter:100.f];
    
    //設置響應的delegate 
    self.locationManager.delegate = self;

六、爲獲取位置作好準備後,就能夠開始定位

    //開啓定位服務
    [self.locationManager startUpdatingLocation];

七、CLLocationManager將根據指定的參數在須要時利用GPS和/或Wi-Fi肯定當前的位置。應實現兩個委託方法,它們分別處理以下情形:位置管理器更新了當前位置或沒法更新當前位置。

獲取位置後,將調用:

//獲取到位置點
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    NSLog(@"%@", locations.lastObject);  //位置管理器經過數組locations提供多個位置,其中最後一個是最新的位置。 
}

沒法更新當前位置將調用 :

//失敗的時候
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    NSLog(@"%@", error);
}
位置管理器可能經過數組locations提供多個位置,其中最後一個是最新的的位置。位置管理器還可能在沒有開始獲取位置時,就快速返回GPS檢測到的最後位置;這種狀況下,若是GPS已關閉且設備發⽣了移動,返回的位置將很不許確。因此要檢查位置的精確度:爲負值或者精確度過差,放棄這些點。若是返回的位置至關精確,就可使用該位置點。在逐步肯定準確位置期間,位置管理器可能調用這個方法屢次,編寫這個方法時必須考慮到這一點。 

 

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    CLLocation *lastLocation = [locations lastObject];
  if(lastLocation.horizontalAccuracy < 0 || lastLocation.horizontalAccu
  racy > 1000){

    return;
  }    
  NSLog(
@">>>>%@",locations.lastObject); }
若是位置管理器未能獲取位置,它將調用 locationManager:didFailWithError: 致使錯誤的緣由多是未獲得用戶的許可,也多是因爲GPS或Wi-Fi不可⽤。發生錯誤時,一般要停⽌位置管理器中止更新當前位置並處理錯誤。 
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    [self.locationManager stopUpdatingLocation];
}

 位置管理器委託可監控航向的變化,這頗有用。可以使用這些信息在地圖上標出用戶的前進路線 相對於正確路線的誤差。要獲取航向信息,須要讓位置管理器對其進行監視。還可設置⼀個可選的篩選器,這樣航向變化小於指定的度數,就不會獲取更新。

CLLocationDegrees degreesFilter = 2.0;
if([CLLocationManager headingAvailable])
{
  [self.locationManager setHeadingFilter:degreesFilter];
  [self.locationManager startUpdatingHeading];
}
發⽣生航向變化事件時,將調⽤用委託⽅方法locationManager:didUpdateHeading: 
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLH
eading *)newHeading{
  NSLog(@"new heading, magnetic%@",newHeading.magneticHeading);
}

八、分析理解位置數據

位置管理器返回的位置是用CLLocation實例表⽰的。CLLocation包含多項有關位置的重要信息,首先是CLLocationCoordinate2D表示經度和緯度。 
CLLocationCoordinate2D coord = lastLocation.coordinate; 
NSLog(@"Locationlat/long: %f,%f",coord.latitude, coord.longitude);
做爲經度和緯度的補充,還有⽔水平精度,它⽤用CLLocationDistance或⽶米數表⽰示。⽔水平精度指的 是實際位置與返回的座標之間的距離在指定⽶米數以內。  
CLLocationAccuracy horizontalAccuracy = lastLocation.horizontalAccuracy;
NSLog(@"Horizontal accuracy: %f meters",horizontalAccuracy);
CLLocation 還提供了當前位置的海拔和垂直精度(單位爲⽶米);若是設備沒有GPS,返回的海拔 將爲零,⽽而垂直精度爲-1。 
CLLocationDistance altitude = lastLocation.altitude;
NSLog(@"Location altitude: %f meters",altitude);
CLLocationAccuracy verticalAccuracy = lastLocation.verticalAccuracy;
NSLog(@"Vertical accuracy: %f meters",verticalAccuracy);

九、重大位置變化通知

Apple強烈建議應用在獲取位置後中止位置更新,以延長電池的續航時間 
一般,在設備位置變化超過500米或更換了鏈接的基站時,將發出通知。另外僅當最後一次通知 是在5分鐘以前時,纔會發送新的通知。
位置更新時間被交給委託⽅方法: locationManager:didUpdateLocations:進⾏行處理。 
//開啓
[self.locationManager startMonitoringSignificantLocationChanges];
//停⽌
[self.locationManager stopMonitoringSignificantLocationChanges];

十、使用GPX文件進行位置測試

GPX文件是GPS交換格式文檔,它使用XML格式,可⽤戶在設備和GPS之間交換信息。在調試模式下,Xcode可以使⽤GPX文件定義的「航點」來設置iOS 模擬器或設備的當前位置。
而且每一個文件能夠添加多個。 
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode"> 
    <wpt lat="37.331705" lon="-122.030237"></wpt>
</gpx>

2、顯示地圖

MapKit 框架爲ios提供了地圖用戶界面功能,其中的基本類型是MKMapView,它顯示地圖、處理用戶與地圖的交互以及管理標註(像⼤頭針)和覆蓋層(如路線圖或突出區域)。 

一、配置和定製MKMapKit

MKMapkit控件在地圖上顯⽰用戶的位置,而且容許⽤戶滾動和放縮;而且能夠調整地圖的類型 
//經過UISegmentedControl切換地圖的區域
- (IBAction)mapTypeSelectionChanged:(id)sender
{
  UISegmentedControl
*mapSelection = (UISegmentedControl *)sender;   switch (mapSelection.selectedSegmentIndex) {     case 0:       [self.mapView setMapType:MKMapTypeStandard];       break;
    case 1:       [self.mapView setMapType:MKMapTypeSatellite];       
break;
    case 2:       [self.mapView setMapType:MKMapTypeHybrid];       
break;     default:       break;   } }
除了設置地圖類型外,另外一種常見的(必須)定製是設置地圖顯示的區域。
   //區域的中心點
    CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(34.78, 113.68);
    //設置經緯度的跨度
    MKCoordinateSpan span = MKCoordinateSpanMake(0.03, 0.03);
    //地圖顯示的區域
    MKCoordinateRegion region = MKCoordinateRegionMake(coordinate, span);
    //設置地圖顯示區域
    [self.mapView setRegion:region];

二、相應用戶交互

可給MkMapView指定委託,以便對⽤戶與地圖互交作出響應。⽤戶與地圖的交互包括平移和放縮、拖拽註釋(annotation)以及用戶輕按標註(callout)時進行響應。 
⽤戶平移或放縮地圖時,將調用委託⽅法mapView:regionWillChangeAnimated:和 mapView:regionDidChangeAnimated:
如何獲取新的地圖區域:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
    MKCoordinateRegion newRegion = [mapView region];
    CLLocationCoordinate2D center = newRegion.center;
    MKCoordinateSpan span = newRegion.span;
    NSLog(@"New map region center: <%f/%f>, span: <%f/%f>",center.latitude,center.longitude,span.latitudeDelta,span.longitudeDelta);
}

 3、地圖註釋和覆蓋層

一、添加註釋

任何對象均可做爲地圖視圖的註釋,前提條件是實現了MkAnnotation協議。Apple建議註釋對象 應該是輕量級的,由於對於添加的每一個註釋,地圖視圖都將包含一個指向它的引用;
另外,註釋太多可能影響地圖的滾動和放縮性能。若是註釋很是簡單,可以使⽤MKPointAnnotation類 (UIKit提供的已經實現了MkAnnotation協議)。 
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    //當前的最準確的位置點
    CLLocation *location = locations.lastObject;        
    //把當前位置做爲註釋添加上
    MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
    //位置指定爲當前位置
    annotation.coordinate = location.coordinate;
    annotation.title = @"你好";
    annotation.subtitle = @"這是銀行";
}

刪除註釋

 [self.mapView removeAnnotations:self.mapView.annotations];

自定義註釋

要實現MKAnnotation,類必須實現屬性coordinate,地圖視圖將使用這個屬性肯定註釋放在地圖的什麼地方。屬性coordinate獲取方法返回一個CLLocationCoordinate2D,同時要存貯其相應的經緯度。
//遵照MKAnnotation協議的對象,能夠做爲註釋
@interface LEAnnotation : NSObject<MKAnnotation>
//其隱性產生了一個get/set方法
@property(nonatomic)CLLocationCoordinate2D coordinate;

//在mapView文件

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{

    if ([annotation isKindOfClass:[LEAnnotation class]]) {

        static NSString *Identifier = @"QYAnnotation";

        MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:Identifier];

        if (!annotationView) {

            annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:Identifier];

        }

        annotationView.annotation = annotation;

        annotationView.image = [UIImage imageNamed:@"currentlocation"];

        return annotationView;

    }

    return nil;

}

二、可拖拽的註釋視圖

可拖拽的註釋視圖頗有用,它讓用戶可以再地圖上指定地點。經過設置屬性draggable設置爲 YES, 讓註釋視圖是可拖拽的。
經過地圖視圖的委託方法, mapView:annotationView:didChangeDragState:fromOldState:,能夠更詳細的瞭解⽤戶是如何 拖拽註釋視圖的。 

三、使用地圖覆蓋層

地圖覆蓋層相似於地圖註釋,能夠是任何實現了協議MKOverlay的對象,⽽地圖視圖委託將負責提供與地圖覆蓋層相關聯的視圖。
地圖覆蓋層不一樣於註釋的地方在於,它們不只能夠表⽰示 點,還能夠表⽰示線段和形狀。所以很是適合⽤於再地圖上表示路線或興趣的區域。 

添加覆蓋層

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    CLLocation *location = locations.lastObject;
    //通過的位置點保存
    [self.allLocation addObject:location];
    //mkmappoint數組
    MKMapPoint *mapArray = malloc(sizeof(MKMapPoint)*self.allLocation.count);
    for (int i = 0; i < self.allLocation.count; i++) {
        CLLocation *location = self.allLocation[i];
        mapArray[i] = MKMapPointForCoordinate(location.coordinate);
    }
    //曲線覆蓋層
    MKPolyline *polyline = [MKPolyline polylineWithPoints:mapArray count:self.allLocation.count];
    free(mapArray);
    //添加覆蓋層
    [self.mapView addOverlay:polyline];
}

當地圖須要顯示地圖覆蓋層的時候, 地圖視圖將調用委託⽅法mapView:viewForOverlay:,這個方法建立⼀個覆蓋層視圖,供地圖進行顯示。有三種形式:圓圈、多邊形、和折線;也可自定義形狀和覆蓋層。 

//返回覆蓋層視圖
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
    if ([overlay isKindOfClass:[MKPolyline class]]) {
        MKPolyline *line = (MKPolyline *)overlay;
        //覆蓋層視圖,曲線
        MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:line];
        renderer.lineWidth = 3.f;
        renderer.strokeColor = [UIColor blueColor];
        //返回覆蓋層
        return renderer;
    }
    return nil;
}
 
相關文章
相關標籤/搜索