iOS 定位和地图

北城余情 提交于 2020-03-01 14:09:59

一、定位

1.1 定位概要

要实现地图、导航功能,往往需要先熟悉定位功能,在iOS中通过Core Location框架进行定位操作。Core Location自⾝可以单独使用,和地图开发框架MapKit完全是独立的,但是往往地图开发要配合定位框架使用。在Core Location 中主要包含了定位、地理编码(包括反编码)功能。

Core Location的主要功能:

1.获取经纬度

2.地理编码(根据给定的地名,获得具体的位置信息(如经纬度、地址的全称等))
3.反地理编码(根据给定的经纬度,获得具体的位置信息)

1.2 iOS 定位功能的实现

导入MapKit框架

     #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;

是否显示用户位置 

     self.mapView.showsUserLocation = YES;
    

授权定位用户的位置,需要在info.plist文件中添加(以下二选一,两个都添加默认使用NSLocationWhenInUseUsageDescription):

  • NSLocationWhenInUseUsageDescription 允许在前台使用时获取GPS的描述
  •  NSLocationAlwaysUsageDescription 允许永远可获取GPS的描述

 

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

定位的精确度


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

    // 1、通过经纬度获取对应的地理位置,查询位置是一个异步操作
    [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.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.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");
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!