地图与定位(二)系统地图

iOS从6.0开始地图服务不再由谷歌驱动,而是改用自家地图,当然在国内它的数据是由高德地图提供的。这样一来,如果在iOS6.0之前进行地图开发的话使用方法会有所不同,基于目前的情况其实使用iOS6.0之前版本的系统基本已经寥寥无几了,所有在接下来的内容中不会再针对iOS5及之前版本的地图开发进行介绍。

在iOS中进行地图开发主要有两种方式,一种是直接利用MapKit框架进行地图开发,利用这种方式可以对地图进行精准的控制;另一种方式是直接调用苹果官方自带的地图应用,主要用于一些简单的地图应用(例如:进行导航覆盖物填充等),无法进行精确的控制。当然,本节重点内容还是前者,系统地图的使用会在后面讲到。


1. 使用MapView显示地图

用MapKit之前需要简单了解一下,MapKit中的类都是以MK开头的,其中用于地图展示的UI控件是MKMapView,下面是MKMapView一些常用属性和方法,具体如下表:

属性 说明
userTrackingMode 跟踪用户当前位置的类型,是一个枚举:MKUserTrackingModeNone :不进行用户位置跟踪;MKUserTrackingModeFollow :跟踪用户位置;MKUserTrackingModeFollowWithHeading :跟踪用户位置并且跟踪用户前进方向;
mapType 地图类型,是一个枚举:MKMapTypeStandard :标准地图,一般情况下使用此地图即可满足;MKMapTypeSatellite :卫星地图;MKMapTypeHybrid :混合地图,加载最慢比较消耗资源;MKMapTypeSatelliteFlyover:3D立体卫星MKMapTypeHybridFlyover:SD立体混合
userLocation 用户位置,只读属性
annotations 当前地图中的所有大头针,只读属性
对象方法 说明
-(void)addAnnotation:(id )annotation; 添加大头针,对应的有添加大头针数组
-(void)removeAnnotation:(id )annotation; 删除大头针,对应的有删除大头针数组
-(void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated; 设置地图显示区域,用于控制当前屏幕显示地图范围
-(void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated; 设置地图中心点位置
-(CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view; 将地理坐标(经纬度)转化为数学坐标(UIKit坐标)
-(CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view; 将数学坐标转换为地理坐标
-(MKAnnotationView )dequeueReusableAnnotationViewWithIdentifier:(NSString )identifier; 从缓存池中取出大头针,类似于UITableView中取出UITableViewCell,为了进行性能优化而设计
-(void)selectAnnotation:(id )annotation animated:(BOOL)animated; 选中指定的大头针
-(void)deselectAnnotation:(id )annotation animated:(BOOL)animated; 取消选中指定的大头针
代理方法 说明
-(void)mapView:(MKMapView )mapView didUpdateUserLocation:(MKUserLocation )userLocation ; 用户位置发生改变时触发(第一次定位到用户位置也会触发该方法,会频繁触发该方法,并反馈用户的位置信息)
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated ; 显示区域发生改变后触发
-(void)mapViewDidFinishLoadingMap:(MKMapView *)mapView; 地图加载完成后触发
-(MKAnnotationView )mapView:(MKMapView )mapView viewForAnnotation:(id )annotation; 显示大头针时触发,返回大头针视图,通常自定义大头针可以通过此方法进行
-(void)mapView:(MKMapView )mapView didSelectAnnotationView:(MKAnnotationView )view 点击选中某个大头针时触发
-(void)mapView:(MKMapView )mapView didDeselectAnnotationView:(MKAnnotationView )view 取消选中大头针时触发
-(MKOverlayRenderer )mapView:(MKMapView )mapView rendererForOverlay:(id )overlay 渲染地图覆盖物时触发

我们先来看一下如何在地图上实现用户位置跟踪,在很多带有地图的应用中默认打开地图都会显示用户当前位置,同时将当前位置标记出来放到屏幕中点方便用户对周围情况进行查看。如果在iOS6或者iOS7中实现这个功能只需要添加地图控件、设置用户跟踪模式、在-(void)mapView:(MKMapView )mapView didUpdateUserLocation:(MKUserLocation )userLocation代理方法中设置地图中心区域及显示范围。但是在iOS8中用法稍有不同:

  • 由于在地图中进行用户位置跟踪需要使用定位功能,而定位功能在iOS8中设计发生了变化,因此必须按照前面定位章节中提到的内容进行配置和请求。
  • iOS8中不需要进行中心点的指定,默认会将当前位置设置中心点并自动设置显示区域范围。

了解以上两点,要进行用户位置跟踪其实就相当简单了,值得一提的是-(void)mapView:(MKMapView )mapView didUpdateUserLocation:(MKUserLocation )userLocation这个代理方法。这个方法只有在定位(利用前面章节中的定位内容)到当前位置之后就会调用,以后每当用户位置发生改变就会触发,调用频率相当频繁。下面是实现用户位置追踪的代码:

示例代码

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

@interface ViewController ()<CLLocationManagerDelegate,MKMapViewDelegate>

@property (nonatomic, strong)CLLocationManager *locationManager;
@property (nonatomic, strong)MKMapView *mapView;

@end

@implementation ViewController

// 定位管家
- (CLLocationManager *)locationManager {

    if (!_locationManager) {

        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
    }
    return _locationManager;
}

// 地图视图
- (MKMapView *)mapView {
    if (!_mapView) {
        _mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
        _mapView.delegate = self;
    }
    return _mapView;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    // 1.判断用户设备定位功能是否开启
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"提醒用户定位服务未开启");
    }

    // 2.判断应用的授权状态,请求用户定位服务授权
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {

        // iOS8以上的版本才需要获取定位授权
        if ([[[UIDevice currentDevice]  systemVersion] floatValue] >= 8.0) {
            //调用此方法之前必须在plist文件中添加NSLocationWhenInUseUsageDescription --string-- 后面跟的文字就是提示信息
            [self.locationManager requestWhenInUseAuthorization];
        }
    }

    // 3.添加地图到界面
    [self.view addSubview:self.mapView];
    [self.view sendSubviewToBack:self.mapView];

    // 4.设置地图的常用属性
    self.mapView.mapType = MKMapTypeStandard;// 设置地图类型
    self.mapView.userTrackingMode = MKUserTrackingModeFollow;// 设置用户追踪模式,不设置设置追踪模式地图不会随用户移动

    // 地图的操作属性
    // 设置对应的属性时,注意该属性是从哪个系统版本开始引入的,做好不同系统版本的适配
    self.mapView.zoomEnabled = YES;// 是否可以缩放
    self.mapView.scrollEnabled = YES;// 是否可以滚动
    self.mapView.rotateEnabled = YES;// 是否可以旋转
    self.mapView.pitchEnabled = YES;// 是否显示3D

    // 地图的显示属性
    self.mapView.showsCompass = YES;// 是否显示指南针
    self.mapView.showsScale = YES;// shif显示比例尺
    self.mapView.showsTraffic = YES;// 是否显示交通状况
    self.mapView.showsBuildings = YES;// 是否显示建筑物
    self.mapView.showsUserLocation = YES;// 是否显示用户的位置:会在地图显示一个蓝色的圆点,标记当前位置,
}

#pragma mark - MKMapViewDelegate
// 加载地图完成后调用,每次地图显示区域发生改变时都会加载地图并调用此方法
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {

    NSLog(@"地图加载完成");
}
/**
 *  方法说明:当用户的位置更新,就会调用(不断地监控用户的位置,调用频率特别高)
 *
 *  @param userLocation 表示地图上蓝色那颗大头针的数据(注意不是那个蓝色的视图,不复写该方法也可以显示蓝色的大头针)
 */
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {

    //用户位置的坐标
    CLLocationCoordinate2D center = userLocation.location.coordinate;
    NSLog(@"%f %f", center.latitude, center.longitude);
    // 可以定义用户位置的大头针属性
    userLocation.title = @"北京";
    userLocation.subtitle = @"天朝帝都";

    // 刷新用户位置时,地图显示的区域默认以用户位置为中心,但是默认显示的区域范围较小,我们可以在这里设置一下地图显示的区域
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 实践发现,在定位刷新结束后立即调用该方法是无法修改地图显示区域的范围的,所以我们延迟调用一下,哪怕仅仅是0.1秒
        [self setMapViewRegin];
    });

}
// 屏幕中显示的地图区域(中心点或是范围)发生变化时调用该方法
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {

    //附近的人,附近的商家,显示的地图区域改变时,显示的数据也需要改变
    NSLog(@"显示的地图范围将要发生变化");
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {

    NSLog(@"显示的地图范围已经发生变化");

    // 地图显示区域
    MKCoordinateRegion region = mapView.region;
    CLLocationCoordinate2D center = region.center;
    NSLog(@"中心点纬度:%f 经度:%f",center.latitude,center.longitude);
    MKCoordinateSpan span = region.span;
    NSLog(@"显示区域范围%f  %f",span.latitudeDelta,span.longitudeDelta);

}

#pragma mark - UIActions
- (IBAction)backUserLocation:(id)sender {

    [self showUserLocation];
//    [self setMapViewRegin];
}

#pragma mark - 私有方法
// 显示用户所在位置
- (void)showUserLocation {
    // 注意该方法应该在确定定位成功之后设置,否则无法获取用户的位置

    // 获取用户位置的坐标
    CLLocationCoordinate2D coordinate = self.mapView.userLocation.location.coordinate;
    [self.mapView setCenterCoordinate:coordinate animated:YES];

}

// 设置地图的显示区域
- (void)setMapViewRegin {
    // 注意该方法应该在确定定位成功之后设置,否则无法获取用户的位置

    // 获取用户位置作为地图显示区域中心
    CLLocationCoordinate2D coordinate = self.mapView.userLocation.location.coordinate;
    // 定义经纬度作为地图显示区域范围
    MKCoordinateSpan span = MKCoordinateSpanMake(1, 1);
    // 定义地图显示的区域
    MKCoordinateRegion regin = MKCoordinateRegionMake(coordinate, span);
    // 设置地图显示区域
    [self.mapView setRegion:regin animated:YES];
}

@end

注意:上面的代码有一个坑点,就是当我们刷新用户位置时,首次看到的地图显示区域是默认的,但是默认显示区域的范围是很小的,我们要想看到跟大的区域只能在代理方法中自行设置,但是我们看到,如果在位置刷新后立即设置的话,是没有任何的效果的。我们需要延迟调用设置显示区域的方法,哪怕仅仅是0.1秒。另外,模拟器默认的坐标为苹果总部,我们可以自定义模拟器所在的地理位置。

另外,在上面的代码中,有几个结构体需要在这里额外的做一些说明:

  • MKCoordinateRegion 用来表示地图显示区域的一个结构体

    typedef struct {

    CLLocationCoordinate2D center;//区域的中心点

    MKCoordinateSpan span;//区域跨度

    } MKCoordinateRegion;

  • CLLocationCoordinate2D 用来表示地理坐标的一个结构体

    typedef struct {

    CLLocationDegrees latitude;// 坐标纬度

    CLLocationDegrees longitude;// 坐标经度

    } CLLocationCoordinate2D;

  • MKCoordinateSpan 用来表示地图显示区域跨度的一个结构体

    typedef struct {

    CLLocationDegrees latitudeDelta;//纬度跨度

    CLLocationDegrees longitudeDelta;//经度跨度

    } MKCoordinateSpan;


2. 添加地图标记

下面我们来看一下iOS中如何在地图中标记位置,运行上面的代码,我们可以在地图上看到一个蓝色的圆点,用来标记用户的位置。在iOS地图开发中经常会需要标记某个位置,需要使用地图标注,也就是大家俗称的“大头针”。

只要一个NSObject类实现MKAnnotation协议就可以作为一个大头针。我们在上面的代码中获取的用户位置数据都是封装在一个MKUserLocation实例对象中的,MKUserLocation就是一个实现了MKAnnotation协议的NSObject子类。但是MKUserLocation的属性大多都是只读的,所以我们不能直接使用MKUserLocation类来保存大头针数据。我们可以自己实现一个NSObject子类并实现MKAnnotation协议作为我们添加的大头针的数据模型。一般我们在自定的子类中重写协议中coordinate(标记位置)、title(标题)、subtitle(子标题)三个属性,然后在程序中创建大头针对象并调用addAnnotation:方法添加大头针即可;

示例代码:

自定义大头针数据模型:

Annotation.h 大头针数据模型

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface Annotation : NSObject<MKAnnotation>

// 大头针标记的地理坐标
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
// 大头针标题
@property (nonatomic, copy) NSString *title;
// 大头针子标题
@property (nonatomic, copy) NSString *subtitle;

@end

根据大头针数据模型,填充地图标记数据,并添加大头针

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

#import "Annotation.h"// 自定义大头针数据模型
@interface ViewController ()<CLLocationManagerDelegate,MKMapViewDelegate>

@property (nonatomic, strong)CLLocationManager *locationManager;
@property (nonatomic, strong)MKMapView *mapView;

@end

@implementation ViewController

- (CLLocationManager *)locationManager
{
    if (!_locationManager) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
    }
    return _locationManager;
}
- (MKMapView *)mapView {

    if (!_mapView) {
        _mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
        //设置mapView的属性
        self.mapView.mapType =  MKMapTypeStandard;//默认
        //设置用户跟踪模式
        self.mapView.userTrackingMode = MKUserTrackingModeFollow;
        _mapView.delegate = self;
    }
    return _mapView;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    // 添加地图
    [self.view addSubview:self.mapView];

    //开启定位服务
    //1.判断手机定位服务是否打开
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"手机定位服务没有打开");
        return;
    }
    //2.iOS8.0以上的用户需要授权
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
        if ([[[UIDevice currentDevice]  systemVersion] floatValue] >= 8.0) {
            //调用此方法之前必须在plist文件中添加NSLocationWhenInUseUsageDescription --string-- 后面跟的文字就是提示信息
            [self.locationManager requestWhenInUseAuthorization];
        }
    }

    //添加单击的手势,添加大头针
    [self.mapView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)]];

}

//将大头针添加到鼠标(手指)点击的地图位置
- (void)tapAction:(UITapGestureRecognizer *)tap {

    //1.获取用户手指触摸屏幕的坐标(x,y)
    CGPoint point = [tap locationInView:tap.view];
    NSLog(@"%@",NSStringFromCGPoint(point));

    //2.将屏幕上的坐标转换成经纬度(数学坐标转换成地理经纬度)
    //- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view;
    CLLocationCoordinate2D location = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
    NSLog(@"(%f,%f)",location.latitude,location.longitude);

    //MKUserLocation属性为只读的,不能作为自定义大头针的类存在
//    MKUserLocation *anno = [[MKUserLocation alloc] init];
//    anno.location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];

    //3.子类化大头针模型,实现大头针协议<MKAnnotation>
    //4.创建大头针
    Annotation *anno = [[Annotation alloc] init];
    anno.coordinate = location;//设置坐标
    anno.title = @"贝沃汇力";
    anno.subtitle = @"iOS 培训的黄埔军校";

    //4.添加
    [self.mapView addAnnotation:anno];
//    self.mapView addAnnotation:<#(nonnull id<MKAnnotation>)#>

}

#pragma mapViewDelegate
/**
 *  用户位置发生改变的时候调用这个方法
 *
 *  @param mapView      地图
 *  @param userLocation 地图上蓝色的那颗大头针数据(注意不是那个蓝色的视图)不复写该方法也可以显示
 */
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    userLocation.title = @"北京市";
    userLocation.subtitle = @"天朝帝都";
    NSLog(@"%f , %f",userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude);
    NSLog(@"%@",userLocation);

    //设置地图显示的区域
    //获取中心点位置
    CLLocationCoordinate2D center = userLocation.location.coordinate;
    //显示跨度
    MKCoordinateSpan span = MKCoordinateSpanMake(3, 3*(375/667));
    //region
    MKCoordinateRegion region = MKCoordinateRegionMake(center,  span);
    [mapView setRegion:region animated:YES];
}

@end
时间: 2024-10-11 23:28:55

地图与定位(二)系统地图的相关文章

Android开发笔记(一百零三)地图与定位SDK

集成地图SDK 国内常用的地图SDK就是百度和高德了,二者的用法大同小异,可按照官网上的开发指南一步步来.下面是我在集成地图SDK时遇到的问题说明: 1.点击基本地图功能选项,不能打开地图,弹出"key验证出错!请在AndroidManifest.xml文件中检查key设置的"的红色字提示.查看日志提示"galaxy lib host missing meta-data,make sure you know the right way to integrate galaxy&

Android应用中使用百度地图API定位自己的位置(二)

官方文档:http://developer.baidu.com/map/sdkandev-6.htm#.E7.AE.80.E4.BB.8B3 百度地图SDK为开发者们提供了如下类型的地图覆盖物: 我的位置图层(MyLocationOverlay):用于显示用户当前位置的图层(支持自定义位置图标): Poi搜索结果图层(PoiOverlay):用于显示兴趣点搜索结果的图层: 路线图层(RouteOverlay):公交.步行和驾车线路图层,将公交.步行和驾车出行方案的路线及关键点显示在地图上(起.终

百度地图开发的学习(二)——地图定位

定位是地图开发的必经重要的环节,我也在不断学习中,就自己了解写一下这些. 一.配置 1.百度的定位是有自己jar包和so文件的,所以记得将它们配置到对应的文件夹中并加载进工程里.具加载方法在学习一里面就有了,这里就不细讲了. 2.在百度的配置方法中导入完库文件后,还要进行声明libs源文件 如果是将jar包和so文件全部放入libs文件中,就需要这样的声明了,本人也试过,但是格式有点偏差,build.gradle会报错,改成下面这样就可以了. sourceSets { main { jniLib

Android百度地图API集成二《定位》

书接上回 ↑ 基础地图请查看Android百度地图API集成一<基础地图>: 地址http://www.cnblogs.com/dhr125/p/5969980.html 1.在Application标签中声明SERVICE组件 <service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote"> <

ios开发系统地图知识

现在很多社交.电商.团购应用都引入了地图和定位功能,地图功能不再是地图应用和导航应用所特有的.目前地图和定位功能已经大量引入到应用开发中.今天就和大家一起看一下iOS如何进行地图开发. 一.Core Location定位使用 在iOS中通过Core Location框架进行定位操作.Core Location自身可以单独使用,和地图开发框架MapKit完全是独立的,但是往往地图开发要配合定位框架使用.在Core Location中主要包含了定位.地理编码(包括反编码)功能. 定位是一个很常用的功

iOS开发——开发实战总结OC篇&amp;地图与定位(LBS)-CoreLocation篇

地图与定位(LBS)-CoreLocation篇 一:地图与定位基本框架(MapKit时基于CoreLocation实现的夜可以实现定位) 二:开发常用技术 LBS:基于位置的服务 SoLoMo:社交,本地,移动化 三:定位授权提示(iOS之前) 四:每个一段距离定位 五:后台服务:默认只能在前台服务 plist文件中 对应plist文件的值(数组) 六:基于基站定位 七:iOS8以上的服务 前台定位 定位服务开启 开启授权 后台服务(可以不勾选后台模式) 定位服务开 开启后台授权 授权改变 /

地图、定位 CLLocationManager CLGeocoder CLPlacemark

地图.定位 一.基本知识点 定位: 1.info.plist文件设置 ios8以后,使用定位需要在info.plist文件中添加两个字段NSLocationAlwaysUsageDescription和NSLocationWhenInUseUsageDescription 2.导入CoreLocation.framework框架并导入头文件 #import <CoreLocation/CoreLocation.h> 3.判断定位服务是否打开 if (![CLLocationManager lo

iOS开发——开发实战总结OC篇&amp;地图与定位(LBS)-MapKit篇

地图与定位(LBS)-MapKit篇 一:MapKit基本介绍 XIB 代码 二:框架没有导入 在Xcode5之后我们不需要在工程中导入苹果的框架,也就是,苹果会自动为神马导入,但是有几个前提 1:你必须import这个框架 2:你必须在项目中使用(需要第一个条件的支持) 只要上面每个条件不满足都会报上名的错误 三:基本属性的使用 1 // 1.设置地图显示类型 2 /** 3 MKMapTypeStandard = 0, // 标准 4 MKMapTypeSatellite, // 卫星 5

地图和定位功能的实现-篇幅略大,手机慎入

来一起学习下地图和定位的使用吧,如有不足,欢迎指正 一.定位功能 1.ios7中的定位 1.1 导入 CoreLocation框架 1.2 创建 CLLocationManager对象 注意:要用强指针指向这个对象,一般采用懒加载来创建 1 private lazy var mgr : CLLocationManager = CLLocationManager() 1.3 设置代理,实现代理方法 1.4 开始定位 mgr.startUpdatingLocation() 1.5 优点:不需要设置用