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

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

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= placemark.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 *[email protected]"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 这就是我使用系统地图是的代码和效果,在这里自己记录一下,也希望可以帮到需要的人,如有问题,请指正!

个人邮箱:[email protected]

时间: 2024-10-13 21:27:11

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

IOS地图定位——IOS8(待更新)

在iOS开发中,使用定位,必须基于2个框架进行开发 (1)Map Kit :用于地图展示 (2)Core Location :用于地理定位 两个热门专业术语 (1)LBS :Location Based Service(基于定位的服务)百度,(高德是定位与导行比较出色) (2)SoLoMo :Social Local Mobile(索罗门)基于位置进行社交 CoreLocation框架的使用 1. 使用前提: 1>导入框架: 2>导入主头文件 #import <CoreLocation/

百度地图可视化定位效果,可以输入目的地定位。

登录百度开发者帐号后下载sdk导入自己的工程中. 代码如下: 1 package com.lixu.baidu_gps; 2 3 import com.baidu.location.BDLocation; 4 import com.baidu.location.BDLocationListener; 5 import com.baidu.location.LocationClient; 6 import com.baidu.location.LocationClientOption; 7 imp

iOS 地图开发小结

首先来说说ios地图开发使用的主要类: MKMapView:地图控件,无其他Label等控件无异,拖进来就可以用了,用于地图的内容的显示,用户可以对地图进行放大.缩小.拖动.旋转等操作: CLLocationCoordinate2D :坐标,包括经度和纬度: MKCoordinateSpan :地图跨度,表示地图放大倍数,数值越小地图显示的单位越精细: CLLocationManager :用户所在位置的管理类,通过该类的能够获取用户所在的GPS坐标. 下面与大家分享一些个人项目中地图部分所涉及

iOS地图导航仪的实现

第一部分 知识储备 1 根据地址定位 苹果给开发者为地址解析提供了CLGeocode工具类,该工具类可以把用户输入的地址解析成经纬度,该方是: -geocodeAddressString:destAddress completionHandler:^(NSArray *placemarks, NSError *error)   该方法将字符串地址解析,然后就可以得到对应的经纬度 2 MKMapView控件及相关属性 <1 ios的MKMapView支持一下三种属性: MKMapTypeStand

室内地图商场停车场室内定位导航拓展方案应用

近几年来.室内位置信息在人们的日常生活中扮演着越来越关键的数据,定位服务市场发展迅速.定位服务需求量迅速增长.比如,医疗行业中重症病人跟踪监护,产房婴儿防盗,贵重医疗设备监控;商场人员定位,顾客消费习惯收集;监狱重点犯人跟踪;展馆.机场导航,实时位置查询服务等.基于互联网的应用要想放到线下.提高线下购物和客户体验度,室内地图行业必将是2015互联网行业必争之地. 上海为卓信息科技自主研发的(SiteMap IMS)室内GIS平台底层架构基于传统GIS平台,依据室内地图和室内定位的特点,在坐标体系

【高德API】如何利用MapKit开发全英文检索的iOS地图

原文:[高德API]如何利用MapKit开发全英文检索的iOS地图 制作全英文地图的展示并不困难,但是要制作全英文的数据检索列表,全英文的信息窗口,你就没办法了吧.告诉你,我有妙招!使用iOS自带的MapKit来展示全球英文底图,结合上高德API的中英文检索功能,就能打造POI数据最丰富,英文展示全方位的纯英文地图啦!看看截图,是不是浑然天成? ----------------------------------------------------------------------------

iOS地图开发MapKit

现在O2O应用非常火,因为基于地理的社交和电子商务应用都有非常广阔的前景 二O2O的移动载体就是手机了(平板基本忽略不计),所以会点手机上Map开发还是不错的 首先苹果已经封装了一套地图框架供我们使用,首先要使用苹果提供的地图框架需要导入MapKit框架 导入完成后即可使用 首先在你的视图里拖入一个MapView, 然后运行就行了~这是你就会看到地图(如果用的是真机最好,模拟器有点蛋疼) 但是现实的是一个大大的地图,赶脚没什么用,我们需要的是一个比较精准的地图,这时进入MKMapView.h文件

iOS 地图开发MapKit和CLLocation

1,iOS 定位服务 现在对iOS下的定组件建进行如下分类: 1>,无限蜂窝定位,根据移动设备距离基站的位置来实现定位的. 2>,GPS定位,也就是所谓的卫星定位,定位精确度较高,但是受遮盖环境影响较大, 3>,无线wifi定位,根据定位路由器的位置,实现定位, 4>,蓝牙beacon定位,定位精确度高,但是要求在外设的覆盖区域内 下面我们主要讲讲iOS下面的定位吧,主要框架CoreLocation.framework,主要对象CLLocationManager,主要代理CLLoc

Vue项目引用百度地图并实现搜索定位等功能

Tip:本篇文章为案例分析,技术点较多,所以篇幅较长,认真阅览的你一定会学到很多知识. 前言:百度地图开放平台 给开发者们提供了丰富的地图功能与服务,使我们的项目中可以轻松地实现地图定位.地址搜索.路线导航等功能.本文给大家介绍如何在vue项目中引用百度地图,并设计实现简单的地图定位.地址搜索功能. 一.效果图及功能点 先来看一下效果图 效果图看不够? 点此 试试在线操作!(初次进入加载较慢,请耐心等待) 功能点: 挂载百度地图 封装逆地址解析函数(根据坐标点获取详细地址) 设置图像标注并绑定拖