LBS(定位服务)pLocation Based Service  ———— 地图

知识点:

1.CoreLocation框架—负责定位的(手机的)位置。用于地理定位
2.MapKit.framework—系统自带的框架,地图展示,
3.ios7 中:系统会自动申请用户位置权限。
CoreLocation中使用 CLLocationManager对象来做用户定位,
CoreLocation框架中所有数据类型的前缀都是 CL
定位的类(位置管理器最好懒加载创建,强引用):CLLocationManager ,用alloc init,创建 ,监听用代理,实现代理方法, 开始更新用户的位置【位置管理器的对象 startUpdatingLocation】,
用来表示经纬度的结构体——CLLocationCoordinate2D 
latitude —纬度  longitude — 经度 course —朝向  timeStamp —更新的点的时间, 测试楼层--floor

4.ios8之后,要做一个判断,如果是,要申请用户权限。代理方法---判断授权状态,status  在Info。plist文件中配置Key值,(当用户在前台还是后台的时候。 请求数据   request。。。。)---代理方法---判断授权状态,

5.调整位置的经纬度—deBug 中的location;

6.位置管理器的常见属性
当用户移动了多长的距离之后,才更新用户的位置(米),对象.distanceFilter =10;
定位精度(精度越高越费电):对象.desiredAccuracy  = kCLLocationAccuracyBestForNavigation;    
extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation; 导航使用最好进度
//    extern const CLLocationAccuracy kCLLocationAccuracyBest;  最高精度
//    extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;  10M
//    extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters; 100M
//    extern const CLLocationAccuracy kCLLocationAccuracyKilometer; 1000M
//    extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers; 3000M
导航的使用场景要用activityType =定位数据的用途 self. locationManager. activityType = CLActivityTypeFitness;
//    CLActivityTypeOther = 1,
//    CLActivityTypeAutomotiveNavigation, // 汽车导航
//    CLActivityTypeFitness, // 步行导航
//    CLActivityTypeOtherNavigation // 其他导航 , 比如轮船 , 火车 , 飞机
//   
CLLocation用来表示某个位置的地理信息,比如经纬度、海拔等等。常见属性
CLLocationCoordinate2D coordinate;表示经纬度
CLLocationDistance altitude;表示海拔
CLLocationDirection course;表示路线,航向(取值范围是0.0° ~ 359.9°,0.0°代表真北方向)
CLLocationSpeed speed;表示行走速度(单位是m/s)

  • 用- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location方法可以计算2个位置之间的距离
  • 计算两个时间点之间的时间差的方法: self.sumTime += [currentLocation.timestamp timeIntervalSinceDate:self.preLocation.timestamp];
计算平均速度案例:
- ( void)locationManager:( CLLocationManager *)manager didUpdateLocations:( NSArray< CLLocation *> *)locations
{
  CLLocation *currentLocation = locations. lastObject;

    if ( self. preLocation == nil) {
        self. preLocation = currentLocation;
        return;
    }
//  计算地图上两点之间的距离 , 以米为单位的
    self. sumDistance += [currentLocation distanceFromLocation: self. preLocation];
    self. sumTime += [currentLocation. timestamp  timeIntervalSinceDate: self. preLocation. timestamp];
   
//  计算平均速度
    CGFloat avgSpeed = self. sumDistance / self. sumTime;
   
    NSLog( @" 总距离 :%lf, 总时间 :%lf, 平均速度 :%lf", self. sumDistance, self. sumTime,avgSpeed);

}
CLHeading:用来表示方向相关的数据
// 更新用户的方向
    [ self. locationManager  startUpdatingHeading];
  • @property(readonly, nonatomic) CLLocationDirection magneticHeading
  • 磁北偏移量, 0度表示磁北, 0 – 359.9
  • 磁北: 磁场北极,是指南针所指的北
  • @property(readonly, nonatomic) CLLocationDirection trueHeading
  • 真北偏移量, 0度表示真北
  • 真北:地理北极, 是地图或者地球仪上所有经线的起始点
设置指南针案例:

#import "ViewController.h"
#import
<CoreLocation/CoreLocation.h>
@interface ViewController ()< CLLocationManagerDelegate>
@property ( weak, nonatomic) IBOutlet UIImageView *compass;指南针
@property( nonatomic, strong) CLLocationManager * locationManager ;
@end

@implementation ViewController
#pragma mark - 懒加载 要在真机上试
-( CLLocationManager *)locationManager{
   
    if (! _locationManager) {
       
        _locationManager = [[ CLLocationManager alloc] init];
       
        _locationManager. delegate = self;
       
    }
    return _locationManager;
}
- ( void)viewDidLoad {
    [ super viewDidLoad];
//   获取用户朝向,没有涉及用户的隐私,不需要请求用户的授权
    // 更新用户的方向
    [ self. locationManager  startUpdatingHeading];
}
#pragma mark - 代理方法
// 当手机的朝向发生改变的时候执行该代理方法   newHeading :用于描述方位的类
-( void)locationManager:( CLLocationManager *)manager didUpdateHeading:( CLHeading *)newHeading{
   
    //    相对于磁北极偏移量 :(0.0 - 359.9 degrees)
    //    newHeading.magneticHeading
    //    相对于真北极的偏移量
    //    newHeading.trueHeading;(0.0 - 359.9 degrees)
   
    double degrees = newHeading. magneticHeading;
   
    // 角度值转换弧度值
    CGFloat angle = degrees / ( 180 / M_PI);
   
    // 由于偏移方向与 transform 的方向是相反的
    self. compass. transform = CGAffineTransformMakeRotation(-angle);
   
}

CLRegion:区域
子类:CLCircularRegion   表示圆形范围:属性:radius 和center

CLLocationCoordinate2D:表示是一个用来表示经纬度的结构体,

typedef struct {

        CLLocationDegrees latitude; // 纬度

        CLLocationDegrees longitude; // 经度


} CLLocationCoordinate2D;
一般用CLLocationCoordinate2DMake函数来创建 CLLocationCoordinate2D


7.计算地图上两点之间的距离(CLLocation
对象) = locations.lastObject;  distanceFromLocation:方法计算两点间的距离


8.监听用户区域( 请求总是授权):【对象  requestAlways Authorization】表示应用不管在前台还是后台,都可以监听用户的地理位置,开发者在Info.plist中设置NSLocationUsageDescription说明定位的目的  
当要监听用户区域改变 , 那么必须请求总是授权


requestWhenInUseAuthorization 只有当前应用在前台的时候 , 才需要使用用户的位置   需要在 info.plist 文件中配置 NSLocationWhenInUseUsageDescription key 来说明使用用户位置的原因

开始监听用户的区域:【  startMonitorngForRegion:】用代理方法(当用户进入监听区域的时候,执行代理方法  didEnterRegion:   离开的时候执行:didExitRegion:)
ClRegion:描述地图上的一块区域的,通常用他的子类 CLCircularRegion  initWithCenter:创建

9.指南针:要生成证书  fix Issue 
获取用户的朝向,没有涉及到用户的隐私。不需要请求用户授权,【对象  startUpdatingHeadIng】——更新用户方向。遵守代理方法 didUpdateHeading:  
newsHeading.magneticHeading ——相对于磁北极:(取值范围:0.0——359.9 degrees角度值—要转为弧度制    degrees / (180/M_PI))在设置指南针的偏移量:transfuse ----用make,弧度值为负的,因为是方向是相反的
相对于真北极的偏移量--------newsHeading.trueHeading


10.CLGeocoder: 可以完成“地理编码”和“反地理编码”  (创建)地理编码器
地理编码:把地名转换成经纬度
反地理编码:把经纬度信息转换成地名
地理编码方法:
- ( void)geocodeAddressString:( NSString *)addressString completionHandler:( CLGeocodeCompletionHandler)completionHandler;
这个方法会访问苹果位置的服务器来返回数据。
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;
  • 城市
例子:
#import "ViewController.h"
#import
<CoreLocation/CoreLocation.h>
@interface ViewController ()
@property ( weak, nonatomic) IBOutlet UITextField *address;

@property ( weak, nonatomic) IBOutlet UITextField *latitude;
@property ( weak, nonatomic) IBOutlet UITextField *longitude;
@property ( weak, nonatomic) IBOutlet UILabel *latitudeLable;
@property ( weak, nonatomic) IBOutlet UILabel *longitudeLable;
@property ( weak, nonatomic) IBOutlet UILabel *addressLable;
@end

@implementation ViewController
#pragma mark - 地理编码
- ( IBAction)Geogidute:( id)sender {
   
    NSString * adress = self. address. text;
   
    if (adress. length == 0) {
       
        NSLog( @" 请输入地名 ");
       
        return;
    }
   
//    地理编码器   创建
    CLGeocoder * geocoder = [[ CLGeocoder alloc] init];
   
    // 地理编码:把地名转换成经纬度   有个方法 这个方法会访问苹果位置的服务器 , 来返回数据
    [geocoder geocodeAddressString:adress completionHandler:^( NSArray< CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
       
//       CLPlacemark 地标:描述了地理的经纬度,地名:省市区
      // 要遍历这个地标,因为地球上相同名字的地方会有很多个
        [placemarks enumerateObjectsUsingBlock:^( CLPlacemark * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
           
//            经纬度
            CLPlacemark * placemark = obj;
           
            CLLocationCoordinate2D coordinate = placemark. location. coordinate;
//            名称
            NSLog( @"%lf,%lf",coordinate. latitude,coordinate. longitude);
            NSLog( @"%@",placemark. name);
           
            NSLog( @"%@ ( 直辖市 ) %@ %@ ",placemark. administrativeArea,placemark. locality,placemark. subLocality);
           
            self. latitudeLable. text = [ NSString stringWithFormat: @"%lf",coordinate. latitude];
           
            self. longitudeLable. text = [ NSString stringWithFormat: @"%lf",coordinate. longitude];
           
            self. addressLable. text = placemark. name;
        }];
       
   
    }];
   
}
反地理编码方法
- ( void)reverseGeocodeLocation:( CLLocation *)location completionHandler:( CLGeocodeCompletionHandler)completionHandler;
例子:
#import "ViewController.h"
#import
<CoreLocation/CoreLocation.h>
@interface ViewController ()
@property ( weak, nonatomic) IBOutlet UITextField *address;

@property ( weak, nonatomic) IBOutlet UITextField *latitude;
@property ( weak, nonatomic) IBOutlet UITextField *longitude;
@property ( weak, nonatomic) IBOutlet UILabel *latitudeLable;
@property ( weak, nonatomic) IBOutlet UILabel *longitudeLable;
@property ( weak, nonatomic) IBOutlet UILabel *addressLable;
@end

@implementation ViewController
#pragma mark - 反地理编码
- ( IBAction)reverseGeogidute:( id)sender {
   
    NSString *latitudeStr = self. latitude. text;
   
    NSString *longitudeStr = self. longitude. text;
   
    if (latitudeStr. length == 0) {
       
        NSLog( @" 请输入纬度信息 ");
        return;
    }
    if (longitudeStr. length == 0) {
       
        NSLog( @" 请输入经度信息 ");
        return;
    }
   
   
    // 创建地理编码器
   
    CLGeocoder * geocoder = [[ CLGeocoder alloc] init];
   
    // 创建位置对象
    CLLocation * location = [[ CLLocation alloc] initWithLatitude:latitudeStr. doubleValue longitude:longitudeStr. doubleValue];
    // 反地理编码
    [ geocoder reverseGeocodeLocation:location completionHandler:^( NSArray< CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
      
        [placemarks enumerateObjectsUsingBlock:^( CLPlacemark * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//            地标
            CLPlacemark * placemark = obj;
           
//            经纬度
            CLLocationCoordinate2D coordinate = placemark. location. coordinate;
           
            NSLog( @"%lf,%lf",coordinate. latitude,coordinate. longitude);
            NSLog( @"%@",placemark. name);
           
            NSLog( @"%@ ( 直辖市 ) %@ %@ ",placemark. administrativeArea,placemark. locality,placemark. subLocality);
           
            self. latitudeLable. text = [ NSString stringWithFormat: @"%lf",coordinate. latitude];
           
            self. longitudeLable. text = [ NSString stringWithFormat: @"%lf",coordinate. longitude];
           
            self. addressLable. text = placemark. name;
           
        }];
    }];
}

系统地图。
1.地图的基本使用
控件栏里的Map View 需要导入对应框架  mapKit.framework 动态库里设置
导入头文件<mapKit>
  • MapKit框架中所有数据类型的前缀都是MK
  • MapKit有一个比较重要的UI控件 :MKMapView,专门用于地图显示
  • 可以通过设置MKMapView的mapViewType设置地图类型
  • MKMapTypeStandard :普通地图
  • MKMapTypeSatellite :卫星云图 
  • MKMapTypeHybrid :混合地国

跟踪显示用户的位置 userTrackingMode 首先要用户授权,
  • 设置MKMapView的userTrackingMode属性可以跟踪显示用户的当前位置
  • MKUserTrackingModeNone :不跟踪用户的位置
  • MKUserTrackingModeFollow :跟踪并在地图上显示用户的当前位置
  • MKUserTrackingModeFollowWithHeading :跟踪并在地图上显示用户的当前位置,地图会跟随用户的前进方向进行旋转
  • MKMapView可以设置一个代理对象,用来监听地图的相关行为
  • 常见的代理方法有
  • - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
  • 一个位置更改默认只会调用一次,不断监测用户的当前位置
  • 每次调用,都会把用户的最新位置(userLocation参数)传进来
  • - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
  • 地图的显示区域即将发生改变的时候调用
  • - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
  • 地图的显示区域已经发生改变的时候调用
  • #pragma mark -用户更新位置时执行
    /// iOS7 中用于显示用户所在地图区域,iOS8以后,可以修改默认的跨度.
    -(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
       
        //   MKCoordinateRegion  用于描述地图一块区域
    //    跨度
        MKCoordinateSpan span = MKCoordinateSpanMake(0.01,0.01);
    //    区域
        MKCoordinateRegion region = MKCoordinateRegionMake(userLocation.location.coordinate, span);
        //  设置地图的显示区域
        [ self.mapView setRegion:region];
       
    }

添加大头针:系统自带的 MKpointAnnotation大头针 模型(标注)——需要经纬度(大头针的点位置)。设置标题title,subTitle子标题在添加到地图上去大头针

自定义大头针:(可以设置样式,大头针颜色(pinColor只有三种颜色 ---canShowCallout这个属性可以出现前面默认设置好的泡泡视图,因为这边涉及到重用。设置泡泡视图的辅助视图用到的属性:left/rightCalloutAccessoryView:button或自定义控件。 ios9新增属性:pinTintColor(各种颜色)),ios8增加的属性:坠落动画:animatesDrop为YES。在代理方法中,mapView:viewForAnnotation:定义 ,返回大头针视图;如果返回nil 就是默认大头针,

if( 模型对象 iskindofclass :模型 class)

自定义大头针设置样式 :定义大头针模型:新建一个类继承自NSObject。在类中,遵从大头针模型协议只会生成get方法。:导入mapkit框架,删除foundation框架。设置属性,枚举类型,

点转换成经纬度的方法:
 
    UITouch *touch = [touches anyObject];

    CGPoint point = [touch locationInView: self. view];
   
    CLLocationCoordinate2D coodinate = [ self. mapView convertPoint:point toCoordinateFromView: self. view];

经纬度转换成点的方法: - ( CGPoint)convertCoordinate:( CLLocationCoordinate2D)coordinate toPointToView:( nullable UIView *)view;



MKMapItem也是地标(创建地图的地标对象)。只有两种使用场景:1.跳转原生地图,2. 计算线路    
1.跳转原生地图:案例
#import "ViewController.h"
#import
<MapKit/MapKit.h>
@interface ViewController ()

@property ( weak, nonatomic) IBOutlet UITextField *startAddress;
@property ( weak, nonatomic) IBOutlet UITextField *endAddress;
@end

@implementation ViewController

- ( IBAction)lookHeading:( id)sender {
   
    NSString * startStr  = self. startAddress. text;
    NSString * endStr  = self. endAddress. text;
    // 判断用户是否输入
    if (startStr. length == 0) {
       
        NSLog( @" 请输入始发地 ");
        return;
    }
    if (endStr. length == 0) {
       
        NSLog( @" 请输入目的地 ");
        return;
    }
   
    // 地理编码
    CLGeocoder * geocoder = [[ CLGeocoder alloc] init];
    [ geocoder geocodeAddressString:startStr completionHandler:^( NSArray< CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
       
        //      多个对象应该如何过滤呢 ?
        //      1. 一般我们遍历 , 然后所在位置是否在用户所在区域
        //      2. 有时候我们也会选用距离用户最近的点
       
        CLPlacemark * placemark = placemarks. lastObject;
        //      MKMapItem 使用场景 : 1. 跳转原生地图 2. 计算线路
        //        [MKMapItem mapItemForCurrentLocation] 当前用户的位置 . 注意如果使用它就必须先请求用户位置权限
        // 创建一个地图的地标对象
        MKPlacemark * startPlacemark = [[ MKPlacemark alloc] initWithPlacemark:placemark];
        MKMapItem * startMapItem = [[ MKMapItem alloc] initWithPlacemark:startPlacemark];
       
        [ geocoder geocodeAddressString:endStr completionHandler:^( NSArray< CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
           
            CLPlacemark * placemark = placemarks. lastObject;
           
            MKPlacemark * endPlacemark = [[ MKPlacemark alloc] initWithPlacemark:placemark];
            MKMapItem * endMapItem = [[ MKMapItem alloc] initWithPlacemark:endPlacemark];
            //           这个方法只能在地图标注一个点
            //            [startMapItem openInMapsWithLaunchOptions:<#(nullable NSDictionary<NSString *,id> *)#>]
           
            //          MKLaunchOptionsDirectionsModeKey 指定导航模式
            //            NSString * const MKLaunchOptionsDirectionsModeDriving; 驾车
            //            NSString * const MKLaunchOptionsDirectionsModeWalking; 步行
            //            NSString * const MKLaunchOptionsDirectionsModeTransit; 动车或者高铁
           
            NSDictionary * lauchOptions = @{ MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeWalking }; // 步行
           
            // 打开原生地图进行导航
            [ MKMapItem openMapsWithItems: @[startMapItem,endMapItem ] launchOptions:lauchOptions];
        }];
       
    }];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值