IOS——地圖與定位

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

Core Location的主要功能:
1.獲取經緯度
2.地理編碼(根據給定的地名,得到具體的位置信息(如經緯度、地址的全 稱等))
3.反地利編碼(根據給定的經緯度,得到具體的位置信息)github

各個類的做用: CLLocation:用於表示位置信息,包含地理座標、海拔等信息,包含在CoreLoaction框架中。app

MKUserLocation:一個特殊的大頭針,表示用戶當前位置。框架

CLPlacemark:定位框架中地標類,封裝了詳細的地理信息。異步

MKPlacemark:相似於CLPlacemark,只是它在MapKit框架中,能夠根據CLPlacemark建立MKPlacemark。ide

##一、定位的基本使用動畫

導入MapKit框架,添加成員變量,簽定MKMapViewDelegate協議 這裏的MKMapView是使用故事板方式建立,在故事板裏面連線設置的協議代理編碼

#import "ViewController.h"
#import <MapKit/MapKit.h>
@interface ViewController ()<MKMapViewDelegate>

@property (weak, nonatomic) IBOutlet MKMapView *mapView;

@property (strong, nonatomic) CLLocationManager *locationManager;

@end

設置地圖的樣式atom

/** 
     MKMapTypeStandard = 0, 平面地圖
     MKMapTypeSatellite, 衛星地圖
     MKMapTypeHybrid, 混合地圖
     MKMapTypeSatelliteFlyover NS_ENUM_AVAILABLE(10_11, 9_0),
     MKMapTypeHybridFlyover**/
   
    self.mapView.mapType = MKMapTypeStandard;

是否顯示用戶位置spa

self.mapView.showsUserLocation = YES;

因爲目前蘋果的iOS系統最新版本爲9,蘋果自iOS8上之後若是要使用定位服務,受權定位用戶的位置,須要在info.plist文件中添加(如下二選一,兩個都添加默認使用NSLocationWhenInUseUsageDescription):

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

判斷當前設備版本大於iOS8之後的話執行裏面的方法

if ([UIDevice currentDevice].systemVersion.floatValue >=8.0) {
        //持續受權
        [locationManager requestAlwaysAuthorization];
        //當用戶使用的時候受權
        [locationManager requestWhenInUseAuthorization];
    }

或者使用這種方式,判斷是否存在這個方法,若是存在就執行,沒有的話就忽略

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

初始化locationManger管理器對象

_locationManager = [[CLLocationManager alloc] init];

設置定位的精確度 kCLLocationAccuracyNearestTenMeters 精確到10米 kCLLocationAccuracyHundredMeters精確到100米kCLLocationAccuracyKilometer 精確到1000米 kCLLocationAccuracyThreeKilometers精確到3000米 kCLLocationAccuracyBest 設備使用電池供電時最高的精度 kCLLocationAccuracyBestForNavigation 導航狀況下最高的精度,通常有外接電源時才能使用

_locationManager.desiredAccuracy = kCLLocationAccuracyBest;

多遠距離更新位置

_locationManager.distanceFilter = 10;

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];
    
}

##二、地圖添加標註視圖

在這裏咱們使用長按手勢添加標註

建立一個長按手勢,並添加到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 *a,NSString *b) {
            
            annotation.title = a;
            annotation.subtitle = b;
        }];
       //地理位置編碼方法
       [self geocoder:coordinate2D];

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

##三、地理位置編碼

添加一個標註,經過點擊位置的經緯度得到標註位置的信息...

建立編碼對象

@property (strong, nonatomic) CLGeocoder *geocoder;

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

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

在手勢方法裏面調用[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);
        }
    }];
}

##四、地理位置反編碼

經過地名得到經緯度

在頁面輸入搜索地點,點擊搜索 搜索按鈕方法

- (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];
       
    }];
}

##五、自定義標註視圖

  • 添加標註視圖時調用,這裏能夠自定義標註視圖
- (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];
    
    if (!annatationView) {
        
        annatationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifer];
        
        //annatationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier: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);
        //能夠設置爲UIImage,可是沒有點擊事件
        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];
        
    }
    
    return annatationView;
}
  • 點擊標註視圖時調用
- (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");
}

Demo下載地址:

https://github.com/fuxinto/HfxDemo

相關文章
相關標籤/搜索