iOS系统定位, 插大头针

CoreLocationManager使用

  • 前言

iOS9.0以后的一个疑问?? didUpdateLocations代理方法中, 速度, 航向根本获取不到?
以下是最基本的初始化功能

定位功能

CoreLocationManager使用

//引入框架, 声明遵守协议
#import 
@interface ViewController ()
    @property (nonatomic, strong)  CLLocationManager *locationManager;
@end
     
- (CLLocationManager *)locationManager
{
    if (_locationManager == nil) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
//        _lm.distanceFilter = 0.5; //每隔多远定位一次, 距离过滤
        /**
         kCLLocationAccuracyBestForNavigation // 最适合导航
         kCLLocationAccuracyBest; // 最好的
         kCLLocationAccuracyNearestTenMeters; // 10m
         kCLLocationAccuracyHundredMeters; // 100m
         kCLLocationAccuracyKilometer; // 1000m
         kCLLocationAccuracyThreeKilometers; // 3000m
         */
        //精确度越高, 耗电, 定位时间长
        _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;//渴望的准确性
        
        
        /** -------iOS8.0+定位适配-------- */
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            //在plist中增加NSLocationWhenInUseUsageDescription和NSLocationAlwaysAndWhenInUsageDescription,两个key
            // 获得在使用中定位的授权
            [_locationManager requestWhenInUseAuthorization];
            //获得前后台定位授权, 这个方法包含上一个方法
            [_locationManager requestAlwaysAuthorization];//
        }
        // 允许后台获取用户位置(iOS9.0)
        if (@available(iOS 9.0, *)) {
            // 如果想要支持后台定位, 下面这个行代码必须写, 前提一定要勾选后台模式 location updates
            _locationManager.allowsBackgroundLocationUpdates = YES;
        } else {
            // Fallback on earlier versions
        }
        
        //9.0之后才有的, 就是在一定时间内按照distanceFilter的枚举来一层一层来定位, 如果超时就走didFailWithError: 方法(注意: 这个方法必须得有, 没有报错)
        if (@available(iOS 9.0, *)) {
//            [_locationManager requestLocation];
        } else {
            // Fallback on earlier versions
        }
    }
    return _locationManager;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    //开始定位
    [self.locationManager startUpdatingLocation];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    //结束定位
    [self.locationManager stopUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *currLocation = [locations lastObject];
    NSLog(@"%@", currLocation);
    self.txtlat.text = [NSString stringWithFormat:@"%f", currLocation.coordinate.latitude];// 纬度
    self.txtLng.text = [NSString stringWithFormat:@"%f", currLocation.coordinate.longitude];//经度
    self.txtAlt.text = [NSString stringWithFormat:@"%f", currLocation.altitude];//高度
}

/**
 *  授权状态发生改变时调用
 *  @param manager 位置管理者
 *  @param status  状态
 */
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
            // 用户还未决定
        case kCLAuthorizationStatusNotDetermined:
        {
        NSLog(@"用户还未决定");
        break;
        }
            // 访问受限
        case kCLAuthorizationStatusRestricted:
        {
        NSLog(@"访问受限");
        break;
        }
            // 定位关闭时和对此APP授权为never时调用
        case kCLAuthorizationStatusDenied:
        {
        // 定位是否可用(是否支持定位或者定位是否开启)
        if([CLLocationManager locationServicesEnabled]) {
            NSLog(@"app定位开启,但被用户拒绝");
        } else {
            NSLog(@"手机硬件定位关闭");
        }
        //            NSLog(@"被拒");
        break;
        }
            // 获取前后台定位授权
        case kCLAuthorizationStatusAuthorizedAlways:
            //        case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
        {
        NSLog(@"获取前台和后台双定位");
        break;
        }
            // 获得前台定位授权
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
        NSLog(@"获得前台定位授权");
        break;
        }
        default:
            break;
    }
}

地理编码

//名字得到经纬度
- (IBAction)geocodeQuery:(id)sender {
   CLGeocoder *geocode = [[CLGeocoder alloc] init];
   [geocode geocodeAddressString:@"杭州" completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
   
       CLPlacemark *placemark = [placemarks firstObject];
       //得到的城市名字
       self.textView.text = placemark.name;
       self.txtLng.text = @(placemark.location.coordinate.longitude).stringValue;// 经度
       self.txtlat.text = @(placemark.location.coordinate.latitude).stringValue;//纬度
   }];
}
//经纬度得到名字
- (IBAction)reverseGeocode:(id)sender {
    CLGeocoder *geocode = [[CLGeocoder alloc] init];
    // 创建CLLocation对象
    CLLocation *location = [[CLLocation alloc] initWithLatitude:[self.txtlat.text doubleValue] longitude:[self.txtLng.text doubleValue]];
    // 根据CLLocation对象进行反地理编码
    [geocode reverseGeocodeLocation:location completionHandler:^(NSArray * __nullable placemarks, NSError * __nullable error) {
        // 包含区,街道等信息的地标对象
        CLPlacemark *placemark = [placemarks firstObject];
        // 城市名称
        //        NSString *city = placemark.locality;
        // 街道名称
        //        NSString *street = placemark.thoroughfare;
        // 全称
        NSString *name = placemark.name;
        self.textView.text = [NSString stringWithFormat:@"%@", name];
    }];
}

插大头针

  1. 首先我们要创建一个大头针的数据模型, 继承NSObject遵守协议
//  MyAnnotation.h
#import 
#import 

@interface MyAnnotation : NSObject
//地理坐标// 用readWrite修饰也行
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
*以上三条是从代理复制过来的
//街道信息
@property (nonatomic, strong) NSString *streetAddress;
//城市信息
@property (nonatomic, strong) NSString *city;
//州, 省市信息
@property (nonatomic, strong) NSString *state;

- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate;

@end
//  MyAnnotation.m
#import "MyAnnotation.h"

@implementation MyAnnotation
 - (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate
{
    self = [super init];
    if (self) {
        self.coordinate = coordinate;
    }
    return self;
}
@end
  1. 将大头针数据模型添加到mapView上

    举例1: 手指点击屏幕时, 获取屏幕坐标对应在地图中的经纬度, 来插大头针, 然后在大头针的标注中显示位置信息

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    //移除其他大头针
    [self.mapView removeAnnotations:self.mapView.annotations];
    //在touchBegan中获取手指点击屏幕坐标
    CGPoint point = [[touches anyObject] locationInView:self.mapView];
    //我们利用mapView的方法来, 利用屏幕坐标point得到mapView地图中的经纬度
    CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
    //来初始化一个地理编码类
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    //初始化一个本地信息, 反地理方法能用到
    CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
    //反地理编码, 给我个坐标, 我告诉你城市, 街道
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
        // 就是取数组最后一个, [placemarks lastObiect]一样
        for (CLPlacemark *placemark in placemarks) {
            MyAnnotation *annotation = [[MyAnnotation alloc] initWithCoordinate:coordinate];//终于创建了大头针了
            annotation.title = placemark.locality;
            annotation.subTitle = placemark.administrativeArea;
            annotation.zip = placemark.postalCode;
            //添加大头针(注: 下面解释3. 大头针的代理方法)
            [self.mapView addAnnotation:annotation];
        }
        if ([placemarks count] > 0) {
            //设置当前手机地图的可视范围, 跟跨度差不多, 但跨度是角度, 东西, 南北跨度, 这个直接写多少米   
            MKCoordinateRegion viewReign = MKCoordinateRegionMakeWithDistance(coordinate, 10000, 10000);
            [self.mapView setRegion:viewReign];
        }
    }];


//当添加[self.mapView addAnnotation: annotation]时系统会回调委托协议MKMapViewDelegate
 — (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation方法, 我们需要实现这个方法, 才能实现在地图上添加标注的操作

例子2. 我们查询一个城市名字, 然后插个大头针子在地图上

[geocoder geocodeAddressString:@"杭州站" completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) {
            for (CLPlacemark *placemark in placemarks) {
                MyAnnotation *annotation = [[MyAnnotation alloc] initWithCoordinate:placemark.location.coordinate];
                annotation.city = placemark.locality;
                annotation.state = placemark.administrativeArea;
                annotation.zip = placemark.postalCode;
  
                annotation.title = annotation.city;
                annotation.subtitle = annotation.state;
                [self.mapView addAnnotation:annotation];
            }

            if ([placemarks count] > 0) {
                MKPlacemark *lastPlacemark = (MKPlacemark *)placemarks.lastObject;
//这个方法可以设置mapView的显示范围(center, 米, 米)
                MKCoordinateRegion viewReign = MKCoordinateRegionMakeWithDistance(lastPlacemark.location.coordinate, 100, 100);
                [self.mapView setRegion:viewReign];
            }
    }];
  1. 大头针的代理方法
//当我们调用 [self.mapView addAnnotation:annotation];方法会来到这个方法
1. 使用系统大头针做的一些改变
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
{
    //MKPinAnnotationView是系统默认的大头针数据模型 ,  这个跟tableView的重用的方式一样
    MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:@"PIN_ANNOTATION"];
    if (annotationView == nil) {
        annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"PIN_ANNOTATION"];
    }
    //是否弹出标注
    annotationView.canShowCallout = true;
    //设置大头针颜色
    annotationView.pinTintColor = [UIColor blackColor];
    //冲天而降
    annotationView.animatesDrop = true;
    
    return annotationView;
}

2. 自定义的大头针
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
{
    static NSString *ID = @"PIN_ANNOTATION";
    MKAnnotationView *annotationView = (MKAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:ID];
    if (annotationView == nil) {
        annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID];
    }
    //必须设置, 默认是不弹出标注
    annotationView.canShowCallout = true;
    //设置大头针为图片
    annotationView.image = [UIImage imageNamed:@"category_5"];
    UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
    iv.image = [UIImage imageNamed:@"htl"];
    
    annotationView.leftCalloutAccessoryView = iv;//标注的辅助视图
   
    annotationView.rightCalloutAccessoryView = iv;//标注的辅助视图
    
    annotationView.detailCalloutAccessoryView = [UISwitch new];//标注的辅助视图
    
    return annotationView;
}

//大头针选中的代理方法, 里面有对应的大头针的数据模型
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
    NSLog(@"纬度:%f----经度:%f", view.annotation.coordinate.latitude, view.annotation.coordinate.longitude);
    
}

- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
    NSLog(@"取消选中");
}

  1. 其他
    // 3D视角
//    MKMapCamera *camer = [MKMapCamera cameraLookingAtCenterCoordinate:CLLocationCoordinate2DMake(23.132931, 113.375924) fromEyeCoordinate:CLLocationCoordinate2DMake(23.135931, 113.375924) eyeAltitude:10];
//    self.mapView.camera = camer;
    
    //地图快照截图
    MKMapSnapshotOptions *option = [[MKMapSnapshotOptions alloc] init];
    // 针对地图
    option.region = self.mapView.region;
    option.showsBuildings = YES;
    
    // 输出图片
    option.size = CGSizeMake(1000, 2000);
    option.scale = [UIScreen mainScreen].scale;
    
    
    MKMapSnapshotter *snap = [[MKMapSnapshotter alloc] initWithOptions:option];
    
    [snap startWithCompletionHandler:^(MKMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
        
        if (error == nil) {
            UIImage *image = snapshot.image;
            
            NSData *data = UIImagePNGRepresentation(image);
            
            [data writeToFile:@"/Users/........" atomically:YES];
        }else
        {
            NSLog(@"--%@", error.localizedDescription);
        }
    }];
  1. 利用ios自带地图导航
//  ViewController.m
//  导航
//
//  Created by JasonBourne on 2018/5/4.
//  Copyright © 2018年 JasonBourne. All rights reserved.
//

#import "ViewController.h"
#import 

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
    request.naturalLanguageQuery = @"沈阳";
    MKLocalSearch *search= [[MKLocalSearch alloc] initWithRequest:request];
    [search startWithCompletionHandler:^(MKLocalSearchResponse * _Nullable response, NSError * _Nullable error) {
        MKMapItem *lastmapItem = [response.mapItems lastObject];
        [lastmapItem openInMapsWithLaunchOptions:@{
                                                   // 导航方式
                                                   MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,
                                                   
                                                   // 地图类型
                                                   MKLaunchOptionsMapTypeKey : @(MKMapTypeHybrid),
                                                   
                                                   // 是否显示交通
                                                   MKLaunchOptionsShowsTrafficKey : @(YES)
                                                   }];
    }];
}

你可能感兴趣的:(iOS系统定位, 插大头针)