您的位置:首页 > 移动开发 > IOS开发

iOS 地图源及目的地定位、划线和系统导航的使用

2016-06-30 17:08 573 查看
最近在做一些关于地图的使用,才发现以前了解的东西很浅,很多细节上的东西没有弄清楚,在这里我想记录一下。好记性不如烂笔头,何况我这烂记性,就更得需要一个好笔头了。废话就不多说,下面就是我在使用系统地图的思路和代码。新手上路,不另指教!

Step1

导入 Mapkit.framework 框架



Step2

引入头文件

#import <MapKit/MapKit.h> //地图框架
#import <CoreLocation/CoreLocation.h> //定位和编码框架


如果只是使用定位,则引入 CoreLocation/CoreLocation.h 即可,需要显示地图则引入MapKit/MapKit.h

Step3

遵守协议和指定代理

@interface MapViewController ()<CLLocationManagerDelegate, MKMapViewDelegate, UITextFieldDelegate>


@property (nonatomic, strong) CLLocationManager *locationManager; //定位管理器

@property (nonatomic, strong) CLGeocoder *geocoder; //创建一个地理编码器,来实现编码和反编码


懒加载创建

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

- (CLGeocoder *)geocoder
{
if (!_geocoder) {
self.geocoder = [[CLGeocoder alloc] init];
}
return _geocoder;
}


Step4

显示地图并定位

- (void)viewDidLoad {

[super viewDidLoad];

[self startLocationUpdate];

self.PYMapView.mapType = MKMapTypeStandard;//选择显示地图的样式
self.PYMapView.delegate = self;//指定代理
/*
*[self.PYMapView setShowsUserLocation:YES];//显示用户位置的小圆点
*/
}

#pragma mark --- 开始定位
- (void)startLocationUpdate
{
//判断用户在设置里面是否打开定位服务
if (![CLLocationManager locationServicesEnabled]) {
NSLog(@"请在设置里面打开定位服务");
}
else{

//获取用户对应用的授权
if ([ CLLocationManager authorizationStatus]== kCLAuthorizationStatusNotDetermined) {

NSLog(@"请求授权");
[self.locationManager requestAlwaysAuthorization];
}
else{

//用户位置追踪(用户位置追踪用于标记用户当前位置,此时会调用定位服务)
self.PYMapView.userTrackingMode = MKUserTrackingModeFollow;//即可以在显示地图的时候定位到用户的位置

self.locationManager.delegate = self;

//设置定位的经纬度精度
_locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
//设置定位频率,每隔多少米定位一次
CLLocationDistance distance = 10.0;
_locationManager.distanceFilter = distance;
//开始定位
[self.locationManager startUpdatingLocation];
}
}
}

#pragma mark --- CLLocationDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
/*
*locations  数组里面存储CLLoction对象, 一个对象代表一个地址
*
*location 中存储  经度 coordinate.longitude、纬度 coordinate.latitude、航向 location.course、速度 location.speed、海拔 location.altitude
*/

CLLocation *location = locations.firstObject;

CLLocationCoordinate2D coordinate = location.coordinate;

NSLog(@"经度:%f,纬度:%f,海拔:%f,航向:%f,行走速度:%f",coordinate.longitude,coordinate.latitude,location.altitude,location.course,location.speed);

[self getAddressByLatitude:coordinate.latitude longitude:coordinate.longitude];

[self.locationManager stopUpdatingLocation];
}


这里就可以根据打印结果获取用户位置了,但是你会发现,然而并本是这样

原因:

iOS8 以后使用系统地图都需要在 info.plist中加入 一下两个字段

NSLocationAlwaysUsageDescription   YES   //一直使用地位服务
NSLocationWhenInUseDescription     YES   //打开应用的时候使用地位服务


根据你的需求添加对应的字段

注: 我使用的是真机(6SP),模拟器地图地位使用不方便。

打印结果:



效果图1:



Step5

使用 GE 进行编码和反编码

/*
*编码与反编码的作用在于: 输入某个位置,根据你输入的位置编码成地理坐标,或根据定位获得的地理坐标反编码成具体的位置信息
*/
#pragma mark 根据地名确定地理坐标
-(void)getCoordinateByAddress:(NSString *)address{

//通过自定义的NSString的延展来判断字符差中不符合要求的情况
if ([NSString isBlankString:address]) {
NSLog(@"输入内容不正确");
return;
}
//地理编码
[self.geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
//取得第一个地标,地标中存储了详细的地址信息,注意:一个地名可能搜索出多个地址
CLPlacemark *placemark=[placemarks firstObject];

CLLocation *location=placemark.location;//位置
CLRegion *region=placemark.region;//区域
NSDictionary *addressDic= pla
ffd8
cemark.addressDictionary;//详细地址信息字典,包含以下部分信息
/*
NSString *name=placemark.name;//地名
NSString *thoroughfare=placemark.thoroughfare;//街道
NSString *subThoroughfare=placemark.subThoroughfare; //街道相关信息,例如门牌等
NSString *locality=placemark.locality; // 城市
NSString *subLocality=placemark.subLocality; // 城市相关信息,例如标志性建筑
NSString *administrativeArea=placemark.administrativeArea; // 州
NSString *subAdministrativeArea=placemark.subAdministrativeArea; //其他行政区域信息
NSString *postalCode=placemark.postalCode; //邮编
NSString *ISOcountryCode=placemark.ISOcountryCode; //国家编码
NSString *country=placemark.country; //国家
NSString *inlandWater=placemark.inlandWater; //水源、湖泊
NSString *ocean=placemark.ocean; // 海洋
NSArray *areasOfInterest=placemark.areasOfInterest; //关联的或利益相关的地标
*/
NSLog(@"位置:%@,区域:%@,详细信息:%@",location,region,addressDic);
NSLog(@"%f-- %f", location.coordinate.latitude, location.coordinate.longitude);

//添加大头针
[self addAnnotationWith:placemark.location.coordinate.latitude Longtitude:placemark.location.coordinate.longitude Placemark:placemark];
//设置为地图中心
[self setCenterWithPlaceMark:placemark];
}];
}

#pragma mark 根据坐标取得地名
-(void)getAddressByLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude{
//反地理编码
CLLocation *location=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
[self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark=[placemarks firstObject];
NSLog(@"详细信息:%@",placemark.addressDictionary);

self.useLocation = placemark.name;

NSLog(@"%@",self.useLocation);
}];
}


#pragma mark --- MapViewDelegate  用户位置持续更新,该方法会一直被调用
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{

NSLog(@"%@",userLocation);
/*
*在需要持续更新用户位置的时候才打开下面的代码
*/
/*
CLLocationCoordinate2D center = userLocation.coordinate;//中心

MKCoordinateSpan span = MKCoordinateSpanMake(0.005, 0.005);//范围

MKCoordinateRegion region = MKCoordinateRegionMake(center, span);

[self.PYMapView setRegion:region animated:YES];
*/
}

//设置地图的中心
- (void)setCenterWithPlaceMark:(CLPlacemark *)placemark
{
CLLocationCoordinate2D center = placemark.location.coordinate;//中心

MKCoordinateSpan span = MKCoordinateSpanMake(0.003, 0.003);//范围

MKCoordinateRegion regiontion = MKCoordinateRegionMake(center, span);

[self.PYMapView setRegion:regiontion animated:YES];
}


现在 就可以定位到用户位置了

Step6

添加大头针 (自定义大头针,icon, title,subtitle)

创建一个继承于 NSObject的类,如下所示:

/*
* 自定义大头针 类
*/
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface PYAnnotation : NSObject<MKAnnotation>

@property (nonatomic, assign) CLLocationCoordinate2D coordinate;//坐标

@property (nonatomic, copy) NSString *title;//标题

@property (nonatomic, copy) NSString *subtitle;//详情

@property (nonatomic,strong) UIImage *image;//自定义一个图片属性在创建大头针视图时使用

@end


记住要遵守 协议, 这样自定义大头针就大功告成了? 幼稚!

我们还需要到控制器去实现一个必须实现的方法,才可以让自定义大头针显示出来,不然会是系统默认的大头针样式

方法如下:

#pragma mark - 地图控件代理方法
#pragma mark 显示大头针时调用,注意方法中的annotation参数是即将显示的大头针对象, 只有该方法实现了才可以显示自定义的大头针图片
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
//由于当前位置的标注也是一个大头针,所以此时需要判断,此代理方法返回nil使用默认大头针视图
if ([annotation isKindOfClass:[PYAnnotation class]]) {

static NSString *key1=@"PYAnnotation";

MKAnnotationView *annotationView = [_PYMapView dequeueReusableAnnotationViewWithIdentifier:key1];

//如果缓存池中不存在则新建
if (!annotationView) {

annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:key1];
annotationView.canShowCallout = true;//允许交互点击
annotationView.calloutOffset = CGPointMake(0, 1);//定义详情视图偏移量
annotationView.leftCalloutAccessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"car"]];//定义详情左侧视图
}
//修改大头针视图
//重新设置此类大头针视图的大头针模型(因为有可能是从缓存池中取出来的,位置是放到缓存池时的位置)
annotationView.annotation = annotation;
annotationView.image = ((PYAnnotation *)annotation).image;//设置大头针视图的图片

return annotationView;
}
else {
return nil;
}
}


现在就可以使用自定义的大头针了

//添加大头针的方法

/*
*方法一:  使用懒加载创建自定义大头针, 哪里需要哪里使用, 就可以保持地图上面只出现一个大头针了(使用场景:在搜索位置的时候,多次输入搜索结果,但只需要为最新的位置添加大头针)
*/
- (PYAnnotation *)annotation
{
if (!_annotation) {

self.annotation = [[PYAnnotation alloc] init];
}
return _annotation;
}
- (void)addAnnotationWith:(CLLocationDegrees)latitude Longtitude:(CLLocationDegrees)longtitude Placemark:(CLPlacemark *)placemark
{
CLLocationCoordinate2D location= placemark.location.coordinate;
self.annotation.title = placemark.locality;
self.annotation.subtitle = placemark.name;
self.annotation.coordinate = location;
self.annotation.image = [UIImage imageNamed:@"flag1"];//大头针图片
[_PYMapView addAnnotation:_annotation];
}
/*
*方法二: 直接创建,每次调用该方法都会创建一个自定义的大头针(使用场景:需要起点、和终点同时添加大头针时,调用该方法便可)
*/
- (void)AnnotationWith:(CLLocationDegrees)latitude Longtitude:(CLLocationDegrees)longtitude Placemark:(CLPlacemark *)placemark ImageName:(NSString *)imageName
{
PYAnnotation *annotation = [[PYAnnotation alloc] init];
CLLocationCoordinate2D location= placemark.location.coordinate;
annotation.title = placemark.locality;
annotation.subtitle = placemark.name;
annotation.coordinate = location;
annotation.image = [UIImage imageNamed:imageName];//大头针图片
[_PYMapView addAnnotation:annotation];
}


效果图2:



Step7

划线,连接输入的终点和起点

/*
*根据输入的内容进行起点和终点的编码
*/
- (void)queryPathWayWithType:(NSString *)type
{
NSLog(@"去这里");

[MBProgressHUD showHUDAddedTo:self.view animated:YES];
//开始编码(先起点)
[self.geocoder geocodeAddressString:self.userPalece completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
CLPlacemark *sourcePlaceMark = [placemarks firstObject];
if (sourcePlaceMark == nil) {
return ;
}
NSLog(@"起点编码成功");

//开始编码(终点)
[self.geocoder geocodeAddressString:self.destionPlace completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
CLPlacemark *destinationPlaceMark = [placemarks firstObject];
if (destinationPlaceMark == nil) {
return ;
}

NSLog(@"编码成功");

if ([type isEqualToString:@"draw"]) {
//两个地标都找到, 就开始划线
[self drawLineWithSource:sourcePlaceMark To:destinationPlaceMark];
}
if ([type isEqualToString:@"navi"]) {
//开始导航
[self startNavigationWithStartPlacemark:sourcePlaceMark endPlacemark:destinationPlaceMark];
}
}];
}];
}
/*
*根据编码结果 进行划线
*/
#pragma mark ---- 划线方法 把起点和终点用线连接,选择不同的模式就会有不同的路线。
- (void)drawLineWithSource:(CLPlacemark *)sourcePlaceMark To:(CLPlacemark *)destinationPlaceMark
{
if (sourcePlaceMark == nil || destinationPlaceMark == nil) {
return;
}
//1、搞清楚方法
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];

request.requestsAlternateRoutes = YES;//进入Api自己看
/*
*MKDirectionsTransportTypeAutomobile //驾车
*MKDirectionsTransportTypeWalking //步行
*MKDirectionsTransportTypeTransit //公交
*MKDirectionsTransportTypeAny //默认
*/
request.transportType = MKDirectionsTransportTypeWalking;
//2、设置起点
MKPlacemark *sourcePM = [[MKPlacemark alloc] initWithPlacemark:sourcePlaceMark];//定位坐标转化为地图坐标
request.source = [[MKMapItem alloc] initWithPlacemark:sourcePM];
//self.sourcePlaceMark = sourcePM;
//3、设置终点
MKPlacemark *destinationPM = [[MKPlacemark alloc] initWithPlacemark:destinationPlaceMark];
request.destination = [[MKMapItem alloc] initWithPlacemark:destinationPM];
//self.destinationPlaceMark = destinationPM;
//4、根据起点和终点开始请求(创建请求方向)
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
//5、发送请求
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) {

if (error) {
//            [MBProgressHUD hideHUD];

[MBProgressHUD hideHUDForView:self.view animated:YES];
NSLog(@"计算路线错误");
return ;
}
NSLog(@"%@", response.routes);
//计算正确, 给计算出来的路线划线
MKRoute *route = response.routes[0];

self.oldLine = route.polyline;

[self.PYMapView addOverlay:route.polyline];

//        for (MKRoute *route in response.routes) {
//
//            //拿出返回结果中存储的所有路线中的需要路线
//            [self.PYMapView addOverlay:route.polyline];
//            self.oldLine = route.polyline;
//        }
//添加大头针
[self AnnotationWith:sourcePlaceMark.location.coordinate.latitude Longtitude:sourcePlaceMark.location.coordinate.longitude Placemark:sourcePlaceMark ImageName:@"start"];
[self AnnotationWith:destinationPlaceMark.location.coordinate.latitude Longtitude:destinationPlaceMark.location.coordinate.longitude Placemark:destinationPlaceMark ImageName:@"dest"];

[MBProgressHUD hideHUDForView:self.view animated:YES];

//设置中心
[self setCenterWithPlaceMark:sourcePlaceMark];
}];
}
#pragma mark ==== 划线的代理方法
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
//在该方法里面划线,设置线的属性
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
renderer.lineWidth = 3;
renderer.strokeColor = [UIColor blueColor];
return renderer;
}


效果图3:



Step8

跳转系统地图 导航

/**
*  利用地标位置开始设置导航
* startPlacemark 开始位置的地标
*  endPlacemark   结束位置的地标
*/
-(void)startNavigationWithStartPlacemark:(CLPlacemark *)startPlacemark endPlacemark:(CLPlacemark*)endPlacemark
{
//0,创建起点
MKPlacemark * startMKPlacemark = [[MKPlacemark alloc]initWithPlacemark:startPlacemark];
//0,创建终点
MKPlacemark * endMKPlacemark = [[MKPlacemark alloc]initWithPlacemark:endPlacemark];

//1,设置起点位置
MKMapItem * startItem = [[MKMapItem alloc]initWithPlacemark:startMKPlacemark];
//2,设置终点位置
MKMapItem * endItem = [[MKMapItem alloc]initWithPlacemark:endMKPlacemark];
//3,起点,终点数组
NSArray * items = @[startItem ,endItem];

//4,设置地图的附加参数,是个字典
NSMutableDictionary * dictM = [NSMutableDictionary dictionary];
//导航模式(驾车,步行)
if ([self.pathType isEqualToString:@"D"]) {
dictM[MKLaunchOptionsDirectionsModeKey] = MKLaunchOptionsDirectionsModeDriving;
}
else if ([self.pathType isEqualToString:@"W"]) {
dictM[MKLaunchOptionsDirectionsModeKey] = MKLaunchOptionsDirectionsModeWalking;
}
else{
dictM[MKLaunchOptionsDirectionsModeKey] = MKLaunchOptionsDirectionsModeTransit;
}
//地图显示的模式
dictM[MKLaunchOptionsMapTypeKey] = MKMapTypeStandard;

//只要调用MKMapItem的open方法,就可以调用系统自带地图的导航
//Items:告诉系统地图从哪到哪
//launchOptions:启动地图APP参数(导航的模式/是否需要先交通状况/地图的模式/..)
[MBProgressHUD hideHUDForView:self.view animated:YES];
[MKMapItem openMapsWithItems:items launchOptions:dictM];
}


效果图4:



End 这就是我使用系统地图是的代码和效果,在这里自己记录一下,也希望可以帮到需要的人,如有问题,请指正!

个人邮箱:18729030047@163.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  iOS系统地图 划线