iOS iOS 地圖與定位開發系列教程

iPhone SDK提供了三個類來管理位置信息:CLLocation CLLocationManager 和 CLLHeading(不常用)。除了使用GPS來獲取當前的位置信息外,iPhone也可以基於WiFi基站和無線發射塔來獲得位置信息。GPS的精度最高,可以精確到米級別,但是也最耗電。

1、CLLocation

CLLocation類代表一個位置信息,其中還包括了方向和速度。比如我在長安街188號以5公里/小時的速度往西走。CLLocation具有下面的屬性和方法:

 

@property  CLLocationCoordinate2D coordinate; //以經度和緯度表示的位置信息
@property CLLocationDistance altitude;  //海拔
@property CLLocationAccuracy horizontalAccuracy; //水平精度(如:精確到米)
@property CLLocationAccuracy verticalAccuracy; //垂直精度
@property CLLocationDirection course; //方向
@property CLLocationSpeed speed; //速度
-(NSDate *)timeStamp;
-(CLLocationDistance)distanceFromLocation:(CLLocation *)location;//兩個位置之間的距離

2、CLLocationManager

CLLocationManager類管理和提供位置服務。它的屬性和方法有:

 

@property CLLocation *location; //位置
@property id<CLLocationManagerDelegate> delegate;
@property CLLocationDistance distanceFilter; //距離過濾,比如:500以內
@property CLlocationAccuracy verticalAccuracy; //垂直精度
-(void) startUpdatingLocation; //開始更新位置(比如:你在往某個地方走)
-(void)stopUpdatingLocation; //停止更新位置
-(void)startUpdatingHeading; //開始更新方向(比如:你改往東走)
-(void)stopUpdatingHeading; //停止更新方向

CLLocationManagerDelegate是一個委託類。你的應用程序需要使用這個委託類。

 

//當用戶改變位置的時候,CLLocationManager回調的方法
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation;

//當用戶改變方向的時候,所調用的方法
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLLHeading *)newHeading;

//當iPhone無法獲得當前位置的信息時,所回調的方法是
-(void)locationManager: (CLLocationManager *)manager didFailLoadWithError:(NSError *)error;

下面我們來看一個位置類的基本步驟:

一、啓動定位服務

CLLocationManager *locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
[locManager startUpdatingLocation];

二、獲得位置信息

 

-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation fromLocation: (CLLocation *)oldLocation
{
NSTimeInterval howRecent = [newLocation.timestamp timeIntervalSinceNow];
if(howRecent < -10) return ; //離上次更新的時間少於10秒
if(newLocation.horizontalAccuracy > 100) return; //精度> 100米
//經度和緯度
double lat = newLocation.coordinate.latitude;
double lon = newLocation.coordinate.longitude;
}

三、獲得方向信息(比如往南走)

-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
//獲得方向
CLLocationDirection heading = newHeading .trueHeading;
}

四、停止定位

[locManager stopUpdatingLocation];

你可以設置你想要的精度和距離過濾:

locManager.desiredAccuracy = kLLocationAccuracyBest;
locManager.distanceFilter = 1000;

MapKit框架主要提供了四個功能
1、顯示地圖;
2、CLLocation和地址之間的轉換;
3、支持在地圖上做標記(比如標記北京天安門廣場);
4、 把一個位置解析成地址(比如我在水立方,想要知道確切的地址信息)。

MKMapView類主要是完成下述功能
1、顯示地圖,比如:顯示北京市的地圖;
2、提供多種顯示方式,比如標準地圖格式,衛星地圖等;
3、支持地圖的放大縮小;
4、支持在地圖上做標記,比如標記天安門廣場;
5、在地圖上顯示手機所在的當前位置。

MKMapView類的屬性有:

 

@property MKCoordinateRegin region; //地圖所顯示的區域
@property CLLocationCoordinate2D centerCoordinate; //經度和緯度確定的中心位置
@property MKMapView mapType; //地圖的顯示類型,如:衛星地圖
@property NSArray *annotations; //地圖上的標記
@property MKUserLocation userLocation; //用戶位置
@property id <MKMapViewDelegate>delegate; //委託類

 

裝載地圖時的回調方法有:

-(void)mapViewWillStartLocationMap:(MKMapView *) mapView; //開始裝載地圖
-(void)mapViewDidFinishLocationMap:(MKMapView  *)mapView; //結束裝載地圖
-(void)mapVewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error; //裝載失敗

當位置發生轉變時的回調方法:

-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated; //將要更改
-(void)mapView: (MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated; //已經更改

MKPlacemark、MKUserLocation和MKReverseGeocoder

在地圖上做標記是通過MKPlacemark類來完成的。這個類使用(符合)MKAnnotation協議。MKAnnotation包含了多個屬性,如:位置(經緯度,CLLocationCoordinate2D類型)、文字標記信息(NSString類型)等。
MKPlacemark保存了位置(經緯度)和地址(字典類)之間的映射。下面是它的初始化方法:

-(void)initWithCoordinate:(CLLocationCoordinate2D *)coordinate addressDictionary:(NSDictionary *)dictionary;

MKUserLocation就是指手機的當前位置,它是MKAnnotation的一個特別案例(因爲MKAnnotation可以是地圖上的任何標記,而MKUserLocation只是標記了地圖上手機所在的當前位置)。這個類包含了多個屬性:手機的位置(類型爲CLLocation)、位置文字信息(類型爲NSString)等。
MKPlacemark保存了位置(經緯度)和地址之間的映射。那麼,有沒有工具在這兩者之間做轉換呢?這就是MKRecerseGeocoder.給定一個位置信息,這個類可以返回相應的地址信息。MKReverseGeocoder的初始化方法爲:

-(void)initWithCoodinate:(CLLocationCoordinate2D)coordinate;

下面是MKReverseGeocoder常用的一些屬性和方法:

@property id <MKReverseGeocoderDelegate>delegate; //委託
-(void)start; //開始轉換
-(void)cancel; //取消轉換

回調的方法有:

-(void)reverseGeocoder:(MKReverseGeocoder *) geocoded didFindPlacemark:(MKPlacemark *)placemark;  //轉換成功
-(void)reverseGeocoder : (MKReverseGeocoder *)geocoded didFailWithError:(NSError *)error; //轉換失敗

iOS MKMapView 基礎

綜述

地圖相關類前綴CL: Core Location。

一.定位

CLLocationManager

The CLLocationManager object is your entry point to the location service.
用於定位

構造方法

 

- (CLLocationManager *)locationManager
{
    if (!_locationManager) {
        //判斷定位功能是否打開
        if ([CLLocationManager locationServicesEnabled]) {
            _locationManager = [[CLLocationManager alloc]init];
            _locationManager.delegate = self;
            [_locationManager requestWhenInUseAuthorization];
            
            //設置尋址精度
            _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
            _locationManager.distanceFilter = 5.0;
            [_locationManager startUpdatingLocation];
        }
    }
    return _locationManager;
}

定位權限

 

- (void)getUserLocationAuthorization{
    //判斷當前設備定位服務是否打開
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"設備尚未打開定位服務");
    }
    
    //判斷當前設備版本大於iOS8以後的話執行裏面的方法
    if ([UIDevice currentDevice].systemVersion.floatValue >=8.0) {
        //當用戶使用的時候授權
        [self.locationManager requestWhenInUseAuthorization];
    }
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
        NSString *message = @"您的手機目前未開啓定位服務,如欲開啓定位服務,請至設定開啓定位服務功能";
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"無法定位" message:message delegate:nil cancelButtonTitle:@"確定" otherButtonTitles: nil];
        [alertView show];
    }
}

設置顯示範圍

遵循CLLocationManagerDelegate協議,實現代理方法

 

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    [self.locationManager stopUpdatingHeading];
    //地址
    self.userLocation = [locations lastObject];
    //顯示範圍
    double latitudeSpan = fabs(self.latitude - self.userLocation.coordinate.latitude) * 3;
    double longitudeSpan = fabs(self.longitude - self.userLocation.coordinate.longitude) *3;
    
    MKCoordinateSpan span = MKCoordinateSpanMake(latitudeSpan, longitudeSpan);
    MKCoordinateRegion regoin = MKCoordinateRegionMake(self.userLocation.coordinate, span);
    [self.mapView setRegion:regoin animated:YES];
}

二.地圖

初始化

 

- (MKMapView *)mapView
{
    if (!_mapView) {
        _mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0,0, kScreenWidth, kScreenHeight)];
        //設置用戶的跟蹤模式
        _mapView.userTrackingMode = MKUserTrackingModeFollow;
        //設置標準地圖
        _mapView.mapType = MKMapTypeStandard;
        // 不顯示羅盤和比例尺
        if (@available(iOS 9.0, *)) {
            _mapView.showsCompass = NO;
            _mapView.showsScale = NO;
        }
        // 開啓定位
        _mapView.showsUserLocation = YES;
        _mapView.delegate = self;
        //初始位置及顯示範圍
        MKCoordinateSpan span=MKCoordinateSpanMake(0.021251, 0.016093);
        [_mapView setRegion:MKCoordinateRegionMake(self.mapView.userLocation.coordinate, span) animated:YES];
    }
    return _mapView;
}

設置覆蓋物

 

- (void)initCarPoint{
    //創建CLLocation 設置經緯度
    CLLocation *loc = [[CLLocation alloc]initWithLatitude:self.latitude longitude:self.longitude];
    CLLocationCoordinate2D coord = [loc coordinate];
    //創建標題
    NSString *titile = @"救護車";
    MSCarPoint *myPoint = [[MSCarPoint alloc] initWithCoordinate:coord andTitle:titile];
    //添加標註
    [self.mapView addAnnotation:myPoint];
}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
    static NSString *placemarkIdentifier = @"PointAnnotation";
    if ([annotation isKindOfClass:[MSCarPoint class]]){
        MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:placemarkIdentifier];
        if([annotation.title isEqualToString:@"救護車"]){
            //救護車
            annotationView.image = [UIImage imageNamed:@"icon"];
        }
        return annotationView;
    }
    return nil;
}

重定位我的位置

 

- (void)resetLocation:(id)sender {
    // 定位到我的位置
    [self.mapView setCenterCoordinate:_mapView.userLocation.coordinate animated:YES];
}

三.地理編碼

CLGeocoder

CLGeocoder: 地理編碼。
地理編碼:根據給定的地名,獲得具體的位置信息(比如經緯度、地址的全稱等)
反地理編碼:根據給定的經緯度,獲得具體的位置信息

CLPlacemark

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;

CLLocation

CLLocation:地理位置

根據地名進行標註代碼實例

 

//初始化地理編碼器
let coder = CLGeocoder()
//根據地名字符串返回CLPlacemark數組和error
coder.geocodeAddressString(area.name) { (placeMark, error) in
    //使用guard進行前置條件判斷,爲空時打印錯誤然後終止方法
    guard placeMark != nil else {
        print(error ?? "未知錯誤")
        return
    }
    //獲取地理位置詳細信息數組中第一個
    let place = placeMark?.first
    //初始化標註
    let annotation = MKPointAnnotation()
    //指定標註標題及副標題
    annotation.title = self.area.name
    annotation.subtitle = self.area.province
    
    //獲取CLPlacemark中的CLLocation
    if let location = place?.location{
        //設置標註經緯度
        annotation.coordinate = location.coordinate
        //顯示標註
        self.mapView.showAnnotations([annotation], animated: true)
        //選中標註
        self.mapView.selectAnnotation(annotation, animated: true)
    }
}

自定義圖釘視圖

遵循MKMapViewDelegate協議,實現如下代理方法。
- (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;
代碼如下。

 

// MARK: - map delegate
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    //判斷是否是用戶位置
    if annotation is MKUserLocation {
        //如果是用戶當前位置,終止方法
        return nil
    }
    //指定標註重用標識符
    let mapId = "myAnnotationId"
    //根據重用標識符獲取標註視圖(與cell重用原理類似)。 注:取出標註視圖轉爲MKPinAnnotationView,自帶圖釘(只自定義左附加視圖圖片)
    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: mapId) as? MKPinAnnotationView
    //判斷標註視圖是否存在
    if annotationView == nil {
        //如果標註視圖不存在,根據標註和標註重用標識符創建標註視圖
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: mapId)
        annotationView?.canShowCallout = true
    }
    //設置自定義icon視圖
    let iconView = UIImageView(frame: CGRect(x: 0, y: 0, width: 53, height: 53))
    iconView.image = UIImage(named: "dislike")
    //設置左附加視圖圖片
    annotationView?.leftCalloutAccessoryView = iconView
    
    //自定義圖釘顏色 IOS9+
    annotationView?.pinTintColor = UIColor.blue
    
    //返回標註視圖
    return annotationView
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章