地图与定位

来源:互联网 发布:大数据 医学的统计 编辑:程序博客网 时间:2024/06/04 23:34
iOS开发中,要想加入地图定位功能,必须基于2个框架进行开发
MapKit :用于地图展示
CoreLocation :用于地理定位

2个热门专业术语
LBSLocationBasedService
SoLoMoSocialLocalMobile(索罗门)

CoreLocation框架的使用
导入主头文件

#import <CoreLocation/CoreLocation.h>

CoreLocation框架使用须知:
CoreLocation框架中所有数据类型的前缀都是CL
CoreLocation中使用CLLocationManager对象来做用户定位

CLLocationManager的常用操作
开始用户定位
- (void)startUpdatingLocation;
停止用户定位
- (void)stopUpdatingLocation;

当调用了startUpdatingLocation方法后,就开始不断地定位用户的位置,中途会频繁地调用代理的下面方法
- (void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray*)locations;
locations参数里面装着CLLocation对象

CLLocation
CLLocation用来表示某个位置的地理信息,比如经纬度、海拔等等
@property(readonly,nonatomic)CLLocationCoordinate2D  coordinate;
经纬度

@property(readonly,nonatomic)CLLocationDistance  altitude;
海拔

@property(readonly,nonatomic)CLLocationDirection  course;
路线,航向(取值范围是0.~359.9°0.0°代表真北方向)

@property(readonly,nonatomic)CLLocationSpeed  speed;
行走速度(单位是m/s

用 - (CLLocationDistance)distanceFromLocation:(constCLLocation*)location方法可以计算2个位置之间的距离

CLLocationManager
@property(assign,nonatomic)CLLocationDistance distanceFilter;
每隔多少米定位一次

@property(assign,nonatomic)CLLocationAccuracy desiredAccuracy;
定位精确度(越精确就越耗电)

CLLocationCoordinate2D

typedef struct {

        CLLocationDegreeslatitude;// 纬度

        CLLocationDegreeslongitude;// 经度

} CLLocationCoordinate2D;

一般用CLLocationCoordinate2DMake函数来创建CLLocationCoordinate2D

示例:
#import "ViewController.h"#import <CoreLocation/CoreLocation.h>@interface ViewController () <CLLocationManagerDelegate>@property(nonatomic,strong)CLLocationManager *mgr;@end@implementation ViewController#pragma mark - 懒加载- (CLLocationManager *)mgr{    if (_mgr == nil) {        // 1.创建定位管理者        _mgr = [[CLLocationManager alloc] init];                // 2.设置代理(我们得通过代理获取用户的位置信息)        _mgr.delegate = self;                // 3.位置间隔之后重新定位        _mgr.distanceFilter = 10;                // 4.定位的精确度        _mgr.desiredAccuracy = kCLLocationAccuracyBestForNavigation;    }    return _mgr;}- (void)viewDidLoad {    [super viewDidLoad];        /*    // 1.创建定位管理者    CLLocationManager *mgr = [[CLLocationManager alloc] init];        // 2.设置代理    mgr.delegate = self;    */    // 3.开始定位    [self.mgr startUpdatingLocation];        // 4.计算两个经纬度之间的距离    [self countDistance];}/** *  计算两个经纬度之间的距离 */- (void)countDistance{    CLLocation *location1 = [[CLLocation alloc] initWithLatitude:23.23 longitude:113.33];    CLLocation *location2 = [[CLLocation alloc] initWithLatitude:40.06 longitude:116.39];        CLLocationDistance distance = [location1 distanceFromLocation:location2];    NSLog(@"%f", distance);}/** *  定位到用户的位置会调用该方法(并且该方法调用非常频繁) * *  @param locations 存放着定位的所有位置 */- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{    // 1.获取用户位置的对象    CLLocation *location = [locations lastObject];    CLLocationCoordinate2D coordinate = location.coordinate;    NSLog(@"纬度:%f 经度:%f", coordinate.latitude, coordinate.longitude);        // 2.停止定位    [manager stopUpdatingLocation];}

CLGeocoder
使用CLGeocoder可以完成“地理编码”和“反地理编码”
地理编码:根据给定的地名,获得具体的位置信息(比如经纬度、地址的全称等)
反地理编码:根据给定的经纬度,获得具体的位置信息

地理编码方法
- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;

反地理编码方法
- (void)reverseGeocodeLocation:(CLLocation*)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;

当地理\反地理编码完成时,就会调用CLGeocodeCompletionHandler
typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks,NSError*error);
这个block传递2个参数
error :当编码出错时(比如编码不出具体的信息)有值
placemarks :里面装着CLPlacemark对象

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;
城市

补充.


1.CLPlacemarkaddressDictionary属性遍历字典数据


addressDictionary enumerateKeysAndObjectsUsingBlock


2.block是在主线程调用,所以可以直接在block刷新UI


name                    :   地名

thoroughfare            :   街道

ubThoroughfare          :   街道相关信息,例如门牌等

locality                :   城市

subLocality             :   城市相关信息,例如标志性建筑

administrativeArea      :   直辖市

subAdministrativeArea   :   其他行政区域信息

postalCode              :   邮编

ISOcountryCode          :   国家编码

country;                :   国家

inlandWater             :   水源、湖泊

ocean;                  :   海洋

areasOfInterest         :   关联的或利益相关的地标




地理编码:
// 地理编码    CLGeocoder *geocoder = [[CLGeocoder alloc] init];    [geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {        // 如果解析有错误,或者解析出的数组个数为0,直接返回        if (placemarks.count == 0 || error) return ;                // 遍历所有的地标对象        for (CLPlacemark *pm in placemarks) {            // 取出用户的位置信息            CLLocation *location = pm.location;            // 取出用户的经纬度            CLLocationCoordinate2D coordinate = location.coordinate;                        // 将信息设置到界面上            self.latitude.text = [NSString stringWithFormat:@"%.2f", coordinate.latitude];            self.longitude.text = [NSString stringWithFormat:@"%.2f", coordinate.longitude];            self.result.text = pm.name;        }    }];

反地理编码:
// 2.反地理编码    CLGeocoder *geocoder = [[CLGeocoder alloc] init];    CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude.floatValue longitude:longitude.floatValue];    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {        // 如果有错误,或者解析出来的地址数量为0        if (placemarks.count == 0 || error) return ;                // 取出地标,就可以取出地址信息,以及CLLocation对象        CLPlacemark *pm = [placemarks firstObject];        #warning 注意:如果是取出城市的话,需要判断locality属性是否有值(直辖市时,该属性为空)        if (pm.locality) {            self.resultLabel.text = pm.locality;        } else {            self.resultLabel.text = pm.administrativeArea;        }    }];

MapKit框架的使用
MapKit框架使用时需要导包
导入主头文件

#import <MapKit/MapKit.h>

MapKit框架使用须知
MapKit框架中所有数据类型的前缀都是MK
MapKit有一个比较重要的UI控件MKMapView,专门用于地图显示

跟踪显示用户的位置
设置MKMapViewuserTrackingMode属性可以跟踪显示用户的当前位置
MKUserTrackingModeNone :不跟踪用户的位置
MKUserTrackingModeFollow 跟踪并在地图上显示用户的当前位置
MKUserTrackingModeFollowWithHeading 跟踪并在地图上显示用户的当前位置,地图会跟随用户的前进方向进行旋转

地图的类型
可以通过设置MKMapViewmapViewType设置地图类型
MKMapTypeStandard普通地图(左图)
MKMapTypeSatellite卫星云图 (中图)
MKMapTypeHybrid普通地图覆盖于卫星云图之上(右图)
                  
MKMapView的代理
MKMapView可以设置一个代理对象,用来监听地图的相关行为

常见的代理方法有
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
一个位置更改默认只会调用一次,不断监测用户的当前位置
每次调用,都会把用户的最新位置(userLocation参数)传进来

- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
地图的显示区域即将发生改变的时候调用

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
地图的显示区域已经发生改变的时候调用

MKUserLocation
MKUserLocation其实是个大头针模型,包括以下属性
@property (nonatomic,copy) NSString*title;
显示在大头针上的标题

@property (nonatomic,copy) NSString*subtitle;
显示在大头针上的子标题

@property (readonly,nonatomic) CLLocation*location;
地理位置信息(大头针钉在什么地方?)

设置地图的显示
通过MKMapView的下列方法,可以设置地图显示的位置和区域
设置地图的中心点位置
@property (nonatomic)CLLocationCoordinate2D  centerCoordinate;
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinateanimated:(BOOL)animated;

设置地图的显示区域
@property (nonatomic)MKCoordinateRegion  region;
- (void)setRegion:(MKCoordinateRegion)regionanimated:(BOOL)animated;
MKCoordinateRegion
MKCoordinateRegion是一个用来表示区域的结构体,定义如下

typedef struct {

        CLLocationCoordinate2D center; //区域的中心点位置

       MKCoordinateSpan span;//区域的跨度

} MKCoordinateRegion;

MKCoordinateSpan的定义

typedef struct {

   CLLocationDegrees latitudeDelta; //纬度跨度

   CLLocationDegrees longitudeDelta; //经度跨度

} MKCoordinateSpan;







ios7地图的基本使用
// 显示地图的View@property (weak, nonatomic) IBOutlet MKMapView *mapView;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];        // 设置代理    self.mapView.delegate = self;        // 跟踪用户的位置    self.mapView.userTrackingMode = MKUserTrackingModeFollow;        // 设置地图类型    self.mapView.mapType = MKMapTypeSatellite;}/** *  定位到用户的位置会执行该方法 * *  @param userLocation 大头针模型 */- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{    // 取出用户的位置    CLLocationCoordinate2D coordinate = userLocation.location.coordinate;    NSLog(@"纬度:%f 经度:%f", coordinate.latitude, coordinate.longitude);        // 改变大头针显示的内容(通过改变大头针模型的属性)    // userLocation.title = @"广州市";    // userLocation.subtitle = @"广东省广州市天河区";    CLGeocoder *geocoder = [[CLGeocoder alloc] init];    CLLocation *location = userLocation.location;    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {        if (placemarks.count == 0 || error) return;                CLPlacemark *pm = [placemarks firstObject];                if (pm.locality) {            userLocation.title = pm.locality;        } else {            userLocation.title = pm.administrativeArea;        }        userLocation.subtitle = pm.name;    }];}

地图的显示区域:
#import "ViewController.h"#import <MapKit/MapKit.h>#define kLatitudeDelta 0.002703#define kLongitudeDelta 0.001717@interface ViewController () <MKMapViewDelegate>// 显示地图的View@property (weak, nonatomic) IBOutlet MKMapView *mapView;/** * 点击之后回到用户的位置 */- (IBAction)backToUserLocation;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];        // 设置代理    self.mapView.delegate = self;        // 跟踪用户的位置    self.mapView.userTrackingMode = MKUserTrackingModeFollow;        // 设置地图类型    // self.mapView.mapType = MKMapTypeSatellite;}/** *  定位到用户的位置会执行该方法 * *  @param userLocation 大头针模型 */- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{    // 取出用户的位置    CLLocationCoordinate2D coordinate = userLocation.location.coordinate;    NSLog(@"纬度:%f 经度:%f", coordinate.latitude, coordinate.longitude);        // 设置mapView显示的中心位置    // [mapView setCenterCoordinate:coordinate animated:YES];    // 设置mapView的显示区域    MKCoordinateSpan span = MKCoordinateSpanMake(kLatitudeDelta, kLongitudeDelta);    MKCoordinateRegion region = MKCoordinateRegionMake(coordinate, span);    [mapView setRegion:region animated:YES];}- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{    MKCoordinateRegion region = mapView.region;    CLLocationCoordinate2D center = region.center;    MKCoordinateSpan span = region.span;    NSLog(@"纬度:%f 经度:%f", center.latitude, center.longitude);    NSLog(@"纬度跨度:%f 经度跨度:%f", span.latitudeDelta, span.longitudeDelta);}// 点击按钮回到用户当前的位置- (IBAction)backToUserLocation {    // 地图的跨度    MKCoordinateSpan span = MKCoordinateSpanMake(kLatitudeDelta, kLongitudeDelta);    // 地图的显示区域    MKCoordinateRegion region = MKCoordinateRegionMake(self.mapView.userLocation.location.coordinate, span);        // 设置地图中心位置为用户的当前位置    // [self.mapView setCenterCoordinate:self.mapView.userLocation.location.coordinate animated:YES];    // 设置地图的显示区域    [self.mapView setRegion:region animated:YES];}

iOS8需要请求授权方式
需要在info.plist文件中添加NSLocationAlwaysUsageDescription字段


// 2.通过判断是否有该方法来判断是否需要请求requestAlwaysAuthorization授权    if ([self.mgr respondsToSelector:@selector(requestAlwaysAuthorization)]) {        [self.mgr requestAlwaysAuthorization];    }


大头针的基本操作
添加一个大头针
- (void)addAnnotation:(id <MKAnnotation>)annotation;
添加多个大头针
- (void)addAnnotations:(NSArray*)annotations;
移除一个大头针
- (void)removeAnnotation:(id <MKAnnotation>)annotation;
移除多个大头针
- (void)removeAnnotations:(NSArray*)annotations;
(id <MKAnnotation>)annotation参数是什么东西?
大头针模型对象:用来封装大头针的数据,比如大头针的位置、标题、子标题等数据

大头针模型
新建一个大头针模型类

#import <MapKit/MapKit.h>

@interface MyAnnotation : NSObject <MKAnnotation>

/**坐标位置*/

@property (nonatomic,assign) CLLocationCoordinate2D coordinate;

/**标题*/

@property (nonatomic,copy) NSString *title;

/**子标题*/

@property (nonatomic,copy) NSString *subtitle;

@end


MKAnnotationView
地图上的大头针控件是MKAnnotationView

MKAnnotationView的属性
@property (nonatomic,strong) id <MKAnnotation> annotation;
大头针模型

@property (nonatomic,strong) UIImage *image;
显示的图片

@property (nonatomic)BOOL  canShowCallout;
是否显示标注

@property (nonatomic)CGPoint  calloutOffset;
标注的偏移量

@property (strong,nonatomic) UIView  *rightCalloutAccessoryView;
标注右边显示什么控件

@property (strong,nonatomic) UIView  *leftCalloutAccessoryView;
标注左边显示什么控件

MKPinAnnotationView
MKPinAnnotationViewMKAnnotationView的子类

MKPinAnnotationViewMKAnnotationView多了2个属性
@property (nonatomic)MKPinAnnotationColor  pinColor;
大头针颜色

@property (nonatomic)BOOL  animatesDrop;
大头针第一次显示时是否从天而降

添加大头针
- (void)viewDidLoad {    [super viewDidLoad];        // 1.设置代理    self.mapView.delegate = self;        // 2.跟踪用户的位置    self.mapView.userTrackingMode = MKUserTrackingModeFollow;        // 3.添加两个大头针    MyAnnotation *anno1 = [[MyAnnotation alloc] init];    anno1.coordinate = CLLocationCoordinate2DMake(40.06, 116.39);    anno1.title = @"北京市";    anno1.subtitle = @"中国北京市昌平区";        MyAnnotation *anno2 = [[MyAnnotation alloc] init];    anno2.coordinate = CLLocationCoordinate2DMake(30.23, 120.23);    anno2.title = @"杭州市";    anno2.subtitle = @"浙江省杭州市萧山区";        [self.mapView addAnnotation:anno1];    [self.mapView addAnnotation:anno2];}/** *  定位到用户的位置会调用该方法 * *  @param userLocation 大头针模型对象 */- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{    // 设置用户的位置为地图的中心点    [mapView setCenterCoordinate:userLocation.location.coordinate animated:YES];}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    // 1.获取用户点击的点    CGPoint point = [[touches anyObject] locationInView:self.view];        // 2.将该点转化成经纬度(地图上的坐标)    CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.view];        // 3.添加大头针    MyAnnotation *anno = [[MyAnnotation alloc] init];    anno.coordinate = coordinate;    anno.title = @"我的位置";    anno.subtitle = @"你猜我在那?";    [self.mapView addAnnotation:anno];}

自定义大头针
/** *  在地图上添加一个大头针就会执行该方法 * *  @param annotation 大头针模型对象 * *  @return 大头针的View(返回nil表示默认使用系统, 默认MKAnnotationView是不可见) */- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{    // 1.如果是用户位置的大头针,直接返回nil,使用系统的    if ([annotation isKindOfClass:[MKUserLocation class]]) return nil;        // 2.创建标识    static NSString *ID = @"annoView";    // 3.从缓冲池中取出大头针的View    MKPinAnnotationView *annoView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID];    // 4.如果为nil,则创建    if (annoView == nil) {        annoView = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:ID];                // 1.设置标题和子标题可以呼出        annoView.canShowCallout = YES;                // 2.设置大头针的颜色        annoView.pinColor = MKPinAnnotationColorPurple;                // 3.掉落效果        annoView.animatesDrop = YES;    }        // 5.设置大头针的大头针模型    annoView.annotation = annotation;        return annoView;}

使用苹果内置地图做导航
#import "ViewController.h"#import <MapKit/MapKit.h>@interface ViewController ()// 目的地的输入框@property (weak, nonatomic) IBOutlet UITextField *destinationField;/** *  点击按钮之后开始导航 */- (IBAction)navigate;@end@implementation ViewController- (IBAction)navigate {    // 1.拿到用户输入的目的地    NSString *destination = self.destinationField.text;    if (destination.length == 0) {        return;    }        // 2.地理编码    CLGeocoder *geocoder = [[CLGeocoder alloc] init];    [geocoder geocodeAddressString:destination completionHandler:^(NSArray *placemarks, NSError *error) {        if (placemarks.count == 0 || error) return ;                // 2.1.取出地理编码出的地标        CLPlacemark *clpm = [placemarks firstObject];                // 2.2.利用CLPlacemark来创建MKPlacemark        MKPlacemark *mkpm = [[MKPlacemark alloc] initWithPlacemark:clpm];                // 2.3.利用MKPlacemark来创建目的地的MKMapItem        MKMapItem *destinationItem = [[MKMapItem alloc] initWithPlacemark:mkpm];                // 2.4.拿到起点的MKMapItem        MKMapItem *sourceItem = [MKMapItem mapItemForCurrentLocation];                // 2.5.开始导航        [self startNavigateWithSourceItem:sourceItem destinationItem:destinationItem];    }];}/** *  开始导航 * *  @param sourceItem      起点的Item *  @param destinationItem 终点的Item */- (void)startNavigateWithSourceItem:(MKMapItem *)sourceItem destinationItem:(MKMapItem *)destinationItem{    // 1.将起点和终点item放入数组中    NSArray *items = @[sourceItem, destinationItem];        // 2.设置Options参数(字典)    NSDictionary *options = @{            MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,            MKLaunchOptionsMapTypeKey : @(MKMapTypeHybrid),            MKLaunchOptionsShowsTrafficKey : @YES                    };        // 3.开始导航    [MKMapItem openMapsWithItems:items launchOptions:options];}


0 0
原创粉丝点击