iOS 定位和地圖

1、定位

1.1 定位概要

要實現地圖、導航功能,每每須要先熟悉定位功能,在iOS中經過Core Location框架進行定位操做。Core Location自⾝能夠單獨使用,和地圖開發框架MapKit徹底是獨立的,可是每每地圖開發要配合定位框架使用。在Core Location 中主要包含了定位、地理編碼(包括反編碼)功能。git

Core Location的主要功能:app

1.獲取經緯度框架

2.地理編碼(根據給定的地名,得到具體的位置信息(如經緯度、地址的全稱等))
3.反地理編碼(根據給定的經緯度,得到具體的位置信息)異步

1.2 iOS 定位功能的實現

導入MapKit框架ide

#import <MapKit/MapKit.h>

簽定MKMapViewDelegate協議 ,添加成員變量動畫

@interface ViewController () <MKMapViewDelegate>
 @property (nonatomic, strong) CLLocationManager* locationManager;
 @end

 

設置地圖的樣式編碼

MKMapTypeStandard = 0, 平面地圖
    MKMapTypeSatellite :衛星雲圖 (中圖)
    MKMapTypeHybrid :混合模式(普通地圖覆蓋於衛星雲圖之上 )
    MKMapTypeSatelliteFlyover: 3D立體衛星 (iOS9.0)
    MKMapTypeHybridFlyover: 3D立體混合 (iOS9.0)
 self.mapView.mapType = MKMapTypeStandard;

是否顯示用戶位置 atom

self.mapView.showsUserLocation = YES;

受權定位用戶的位置,須要在info.plist文件中添加(如下二選一,兩個都添加默認使用NSLocationWhenInUseUsageDescription):spa

  • NSLocationWhenInUseUsageDescription 容許在前臺使用時獲取GPS的描述
  •  NSLocationAlwaysUsageDescription 容許永遠可獲取GPS的描述

 

if ([CLLocationManager instanceMethodForSelector:@selector(requestWhenInUseAuthorization)]) {
        
        [self.locationManager requestWhenInUseAuthorization];
    }
}

定位的精確度rest

kCLLocationAccuracyBestForNavigation // 最適合導航
    kCLLocationAccuracyBest; // 最好的
    kCLLocationAccuracyNearestTenMeters; // 10m
    kCLLocationAccuracyHundredMeters; // 100m
    kCLLocationAccuracyKilometer; // 1000m
    kCLLocationAccuracyThreeKilometers; // 3000m
    // 精確度越高, 越耗電, 定位時間越長
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;

每一個多少米定位一次

_locationManager.distanceFilter = 10;

1.3 地理位置編碼

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

對應方法

  • 地理編碼方法-(void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler


建立編碼對象

@property (strong, nonatomic) CLGeocoder *geocoder;

建立一個block做爲參數傳遞的方式

@property (strong, nonatomic) void(^geocodeComplatHandle)(NSString *name);

在手勢方法裏面調用[self geocoder:coordinate2D]方法傳遞一個經緯度進去

- (void)geocoder:(CLLocationCoordinate2D)coordinate2D {

    // 建立一個經緯度位置 CLLocation
    CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate2D.latitude longitude:coordinate2D.longitude];

    // 一、經過經緯度獲取對應的地理位置,查詢位置是一個異步操做
    [self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {

        CLPlacemark *placemark = [placemarks lastObject];

        NSLog(@"%@ %@ %@",placemark.name, placemark.thoroughfare,placemark.subThoroughfare);

        // 將地理位置名稱顯示在標註視圖上
        if (self.geocodeComplatHandle) {

            self.geocodeComplatHandle(placemark.name,placemark.thoroughfare);
        }
    }];
}

1.4 地理位置反編碼

對應方法

  • 反地理編碼方法-(void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler

反地理編碼(根據給定的經緯度,得到具體的位置信息)

- (IBAction)search:(id)sender {

    [self.geocoder geocodeAddressString:self.searchText.text completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {

        CLPlacemark *placemark = placemarks[0];

        //建立並添加一個標註視圖到mapView上
        MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
        annotation.coordinate = placemark.location.coordinate;
        //將標註添加到地圖上
        [self.mapView addAnnotation:annotation];

    }];
}

2、地圖

2.1 地圖(MapKit的基本概念)

在iOS6之後,蘋果再也不使用蘋果地圖,⽽是使用蘋果⾃己的地圖。咱們使用Core Location來獲取⽤戶的位置信息,MapKit則是⽤來顯⽰具體的信息。其核心是MKMapView類的使用,咱們能夠設置地圖顯示方式,控制地圖,能夠在地圖上添加標註。

2.2 地圖類型

  •  MKMapTypeStandard : 平面地圖
  • MKMapTypeSatellite :衛星雲圖 (中圖)
  • MKMapTypeHybrid :混合模式(普通地圖覆蓋於衛星雲圖之上 )
  • MKMapTypeSatelliteFlyover: 3D立體衛星 (iOS9.0)
  • MKMapTypeHybridFlyover: 3D立體混合 (iOS9.0)

 

 MKMapViewDelegate協議方法

#pragma mark - <MKMapViewDelegate>

// 地圖加載完成
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {
    
    NSLog(@"%s %f, %f",__func__, mapView.userLocation.coordinate.longitude, mapView.userLocation.coordinate.latitude);
    }

// 用戶位置更新後調用
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
    
    //設置中心點
    CLLocationCoordinate2D center = userLocation.location.coordinate;
    
    // 設置跨度
    MKCoordinateSpan span = {0.01,0.01};
    
    // 設置地圖顯示的範圍
    [self.mapView setRegion:MKCoordinateRegionMake(center, span) animated:YES];
    
    NSLog(@"用戶位置發生改變");
}

2.3 MKMapView添加標註視圖

使用長按手勢添加標註,建立一個長按手勢,添加到mapView上面

UILongPressGestureRecognizer *longGest = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longGestAction:)];

[self.mapView addGestureRecognizer:longGest];

手勢方法實現

- (void)longGestAction:(UILongPressGestureRecognizer *)longGest {

    // 獲取觸摸點所在地圖上的CGPoint座標
    CGPoint point = [longGest locationInView:self.mapView];

    // 將地圖所在觸摸點的座標 CGPoint 轉爲對應的經緯度 CLLocationCoordinate2D
    CLLocationCoordinate2D coordinate2D = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];

    if (longGest.state == UIGestureRecognizerStateBegan) {

        // 建立並添加一個標註視圖到mapView上
        MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
        annotation.title = @"XXXX";
        annotation.coordinate = coordinate2D;
        annotation.subtitle = [NSString stringWithFormat:@"%f, %f",annotation.coordinate.latitude, annotation.coordinate.longitude];

        [self setGeocodeComplatHandle:^(NSString *locationName1,NSString *locationName2) {

            annotation.title = loationName1;
            annotation.subtitle = locationName2;
        }];
       // 地理位置編碼方法
       [self geocoder:coordinate2D];

        // 將標註添加到地圖上
        [self.mapView addAnnotation:annotation];
    }

}

3、自定義標註視圖

3.1 步驟:

1.⾃定義實現MKAnnotation的類並從新coordinate,title,subtitle屬性。

2.實現MKMapViewDelegate的- mapView:viewForAnnotation: 方法。

自定義標註視圖功能實現:
用戶位置發生改變後調用

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
    
    CLLocationCoordinate2D center = userLocation.location.coordinate;
    MKCoordinateSpan span = {0.05,0.05};
    [mapView setRegion:MKCoordinateRegionMake(center, span) animated:YES];
}

添加了標註視圖後調用

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views {
    
    NSLog(@"添加了標註視圖後調用");
}

 添加標註視圖時調用,這裏能夠自定義標註視圖

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    
    NSLog(@"viewForAnnotation");
    
    // 判斷是不是用戶當前的位置標註
    if (![annotation isKindOfClass:[MKPointAnnotation class]]) {
        
        return nil;
    }
    //設置重用標示符
    static NSString *identifer = @"annotation";
    //先從重用的隊列中找
    MKAnnotationView *annatationView = [mapView dequeueReusableAnnotationViewWithIdentifier:identifer];

大頭針樣式

// MKPinAnnotationView *annatationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifer];

 是否顯示輔助標註視圖

annatationView.canShowCallout = YES;

設置大頭針的顏色,前提是爲MKPinAnnotationView類型

annatationView.pinTintColor = [UIColor orangeColor];

設置大頭針出現的動畫,前提是爲MKPinAnnotationView類型

annatationView.animatesDrop = YES;

 使用圖片做爲標註

annatationView.image = [UIImage imageNamed:@"icon"];

 是否能夠拖拽

annatationView.draggable = YES;

設置標註視圖的偏移

annatationView.centerOffset = CGPointMake(0, -25);

設置輔助視圖的偏移

annatationView.calloutOffset = CGPointMake(0, -10);
        
      UIButton *leftView = [UIButton buttonWithType:UIButtonTypeCustom];
      [leftView setImage:[UIImage imageNamed:@"頭像"] forState:UIControlStateNormal];
      leftView.tag = 100;
      leftView.frame = CGRectMake(0, 0, 50, 50);

設置左邊的輔助視圖

annatationView.leftCalloutAccessoryView = leftView;

 設置右邊的輔助視圖

annatationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];

點擊標註視圖時調用

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {

    NSLog(@"didSelectAnnotationView");
}

點擊左右輔助視圖時調用

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {

    NSLog(@"%@",control);
}

地圖開始加載時調用

- (void)mapViewWillStartLoadingMap:(MKMapView *)mapView {

    NSLog(@"地圖開始加載時調用");
}

地圖加載完成時調用

- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {

    NSLog(@"地圖加載完成時調用");
}

地圖加載失敗時調用

- (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error {

    NSLog(@"地圖加載失敗時調用");
}

地圖顯示的範圍將要發生改變時調用

- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {

    NSLog(@"地圖顯示的範圍將要發生改變時調用");
}

地圖顯示的範圍改變後調用

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {

    NSLog(@"地圖顯示的範圍改變後調用");
}

定位用戶的位置失敗

- (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error {

    NSLog(@"定位用戶的位置失敗");
}

標註視圖拖拽後調用

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState
   fromOldState:(MKAnnotationViewDragState)oldState {

    /** 拖拽的狀態
        MKAnnotationViewDragStateNone = 0, 沒有拖拽
        MKAnnotationViewDragStateStarting, 開始拖拽
        MKAnnotationViewDragStateDragging, 正在拖拽
        MKAnnotationViewDragStateCanceling, 取消拖拽
        MKAnnotationViewDragStateEnding 結束拖拽
     **/

    NSLog(@"didChangeDragState");
}
相關文章
相關標籤/搜索