IOS高德地图实现关键字搜索位置,路径规划和模拟车辆运行路线动画(车头改变方向)

路径规划示意图

Demo集成初衷

本人上手的第一个项目就是基于高德地图,对于地图开发兴趣浓厚,2018年初步了解了高德地图的sdk,遇到了很多不懂的,也慢慢的研究了出来,最近在回顾的时候发觉还有好多地图的功能自己还不熟悉,决定再次深入研究。

本文研究内容

一.关键字搜索地理位置
二.路径规划
三.小车轨迹移动动画,车辆的暂停,继续运动
四.实时导航

正文

关键字搜索地理位置

首先导入需要用到的库

#import <MAMapKit/MAMapKit.h>
#import <AMapFoundationKit/AMapFoundationKit.h>
#import <AMapSearchKit/AMapSearchKit.h>

遵循协议

<MAMapViewDelegate,AMapSearchDelegate,UITextFieldDelegate>

在控制器中将地图添加进去,先让地图显示出来

self.mapView = [[MAMapView alloc] initWithFrame:self.view.bounds];
self.mapView.showsIndoorMap = YES;
self.mapView.delegate = self;
self.mapView.showsUserLocation = true;
self.mapView.userTrackingMode = MAUserTrackingModeFollow;
self.mapView.zoomLevel = 10;
[self.view addSubview:self.mapView];
[self.view sendSubviewToBack:self.mapView];

自己在界面中加一个UITextView,我是放在了顶部的位置,用来获取输入的搜索内容
在UITextView的监听回调方法中,点击搜索之后调用高德地图API

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    AMapInputTipsSearchRequest *tips = [[AMapInputTipsSearchRequest alloc] init];
    tips.keywords = textField.text;
    tips.city     = kSearchCity;
    tips.cityLimit = YES;
    
    [self.search AMapInputTipsSearch:tips];
    
    return [textField resignFirstResponder];
}

同时要添加回调方法,我这里用for循环将搜索获取到的位置添加到地图中

/* 输入提示回调. */
- (void)onInputTipsSearchDone:(AMapInputTipsSearchRequest *)request response:(AMapInputTipsSearchResponse *)response
{    
    if (response.count == 0)
    {
        return;
    }
    
    [self.tips setArray:response.tips];
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.mapView removeAnnotations:self.mapView.annotations];
            
                for (AMapTip *tip in self.tips) {
                    if (tip.uid != nil && tip.location != nil) /* 可以直接在地图打点  */
                    {
                        AMapTipAnnotation *annotation = [[AMapTipAnnotation alloc] initWithMapTip:tip];
                        [self.mapView addAnnotation:annotation];
                        [self.mapView selectAnnotation:annotation animated:YES];
                    }
                }
    });

    
}

viewForAnnotation方法中给地图兴趣点设置了属性,主要是marker的图标

//地图上的起始点,终点,拐点的标注,可以自定义图标展示等,只要有标注点需要显示,该回调就会被调用
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation {

    if ([annotation isKindOfClass:[POIAnnotation class]] || [annotation isKindOfClass:[AMapTipAnnotation class]])
    {
        static NSString *tipIdentifier = @"poiIdentifier";
        
        MAPinAnnotationView *poiAnnotationView = (MAPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:tipIdentifier];
        if (poiAnnotationView == nil)
        {
            poiAnnotationView = [[MAPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:tipIdentifier];
        }
        
        poiAnnotationView.canShowCallout = YES;
        poiAnnotationView.image = [UIImage imageNamed:@"placeAnnotation"];
        
        return poiAnnotationView;
    }
   
    return nil;
}

到这里根据关键字搜索位置并将兴趣点添加到地图中已经实现,搜索还有很多种API方法,这里用的是AMapInputTipsSearchRequest,还有就是不同的API,对应的回调方法也会不太一样,这个需要注意。

编辑日期:2020/1/13

——————————————————————分割线——————————————————

路径规划

路径规划的原理是传入起点和终点位置的坐标,利用高德地图提供的API AMapRidingRouteSearchRequest 去发起请求,请求的结果存在成功与失败,具体信息在回调方法中体现出来

自定义一个带有起始点经纬度参数的方法

- (void)setUpPosition:(CLLocationCoordinate2D )startCoordinate  destinationCoordinate:(CLLocationCoordinate2D )destinationCoordinate {
    
    self.startAnnotation.coordinate = startCoordinate;
    self.destinationAnnotation.coordinate = destinationCoordinate;

    AMapRidingRouteSearchRequest *navi = [[AMapRidingRouteSearchRequest alloc] init];

    /* 出发点. */
    navi.origin = [AMapGeoPoint locationWithLatitude:self.startCoordinate.latitude
                                           longitude:self.startCoordinate.longitude];
    /* 目的地. */
    navi.destination = [AMapGeoPoint locationWithLatitude:self.destinationCoordinate.latitude
                                                longitude:self.destinationCoordinate.longitude];
    
    [self.search AMapRidingRouteSearch:navi];
}

响应的回调方法

/* 路径规划搜索成功回调. */
- (void)onRouteSearchDone:(AMapRouteSearchBaseRequest *)request response:(AMapRouteSearchResponse *)response

/* 路径规划搜索失败回调. */
- (void)AMapSearchRequest:(id)request didFailWithError:(NSError *)error

在rendererForOverlay方法中设置路径的样式

//地图上覆盖物的渲染,可以设置路径线路的宽度,颜色等
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id<MAOverlay>)overlay

路径规划成功后,选择一条路径并添加到地图上,我这里默认选择的是第一条

//在地图上显示当前选择的路径
- (void)onRouteSearchDone {
    
    if (self.totalRouteNums <= 0) {
        return;
    }
    
    [self.naviRoute removeFromMapView];  //清空地图上已有的路线
        
    MANaviAnnotationType type = MANaviAnnotationTypeDrive; //骑行类型
    
    AMapGeoPoint *startPoint = [AMapGeoPoint locationWithLatitude:self.startAnnotation.coordinate.latitude longitude:self.startAnnotation.coordinate.longitude]; //起点
    
    AMapGeoPoint *endPoint = [AMapGeoPoint locationWithLatitude:self.destinationAnnotation.coordinate.latitude longitude:self.destinationAnnotation.coordinate.longitude];  //终点
    
    //根据已经规划的路径,起点,终点,规划类型,是否显示实时路况,生成显示方案
    self.naviRoute = [MANaviRoute naviRouteForPath:self.route.paths[0] withNaviType:type showTraffic:NO startPoint:startPoint endPoint:endPoint];
    
    [self.naviRoute addToMapView:self.mapView];  //显示到地图上
    
    [SVProgressHUD dismiss];
    
    
}

自由发挥的空间也挺大,可以设置其他出行方式,我这里设置的是骑行,路径规划的功能到这里基本就实现了,具体的内容需要结合Demo学习。

编辑日期:2020/1/14

——————————————————————分割线——————————————————

小车移动动画(车头方向改变)

小车移动动画的原理分为以下几个步骤:

  • 实例化小车,将小车作为marker添加到地图中,给小车添加代理方法,监听小车的运动过程
  • 获取到小车移动路线图中路过的经纬度组成的点(我在路径规划后获取到了路径中的位置点,去重存在数组中了)
  • 执行小车移动的动画函数(高德地图API提供)

继承MAAnimatedAnnotation新建一个小车的动画类,控制车头方向改变,暂停和继续行驶,这个在Demo中有了直接用


车头改变方向,暂停和继续的动画类

在获取到搜索内容之后点击其中任意一个兴趣点,在didSelectAnnotationView方法中可以获取到该点的经纬度

- (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view 

点击路径规划按钮之后会在地图上绘制从当前位置到目的地的路线图

我这里做的处理是分段执行动画,简单说就是一共有多少组点,就执行了多少次动画,目的是在回调方法中给小车走过的路线上绘制路线,设置其他颜色,当然也可以一次性执行动画,参数中传入数组和数组对应的索引数量就可以了。

这是执行的小车移动动画函数,具体参数含义看代码注释,我这里给小车定义了一个车速,可以控制小车执行动画的速度

/**
 @brief 添加移动动画, 第一个添加的动画以当前coordinate为起始点,沿传入的coordinates点移动,否则以上一个动画终点为起始点. since 4.5.0
 @param coordinates c数组,由调用者负责coordinates指向内存的管理
 @param count coordinates数组大小
 @param duration 动画时长,0或<0为无动画
 @param name 名字,如不指定可传nil
 @param completeCallback 动画完成回调,isFinished: 动画是否执行完成
 */
- (MAAnnotationMoveAnimation *)addMoveAnimationWithKeyCoordinates:(CLLocationCoordinate2D *)coordinates
                                                            count:(NSUInteger)count
                                                     withDuration:(CGFloat)duration
                                                         withName:(NSString *)name
                                                 completeCallback:(void(^)(BOOL isFinished))completeCallback;

小车移动与暂停的原理是控制以下方法的执行与否

/**
 * @brief 动画帧更新回调接口,实现者可在内部做更新处理,如更新coordinate. (since 4.5.0)
 * @param timeDelta 时间步长,单位秒
 */
- (void)step:(CGFloat)timeDelta;

这个方法在监听小车移动的整个过程,不执行该方法小车就停止运动,执行就继续运动,在控制器中可以设置一个Bool值,点击按钮取反判断方法的执行

代码贴的不多,主要是讲解原理,具体代码可以在Demo中细看,到这里就完成了本文的三个研究内容的大致阐述,后续还会继续添加新功能,方便初学者快速上手。

编辑日期:2020/1/15

——————————————————————分割线——————————————————

我又来了

今天是复工的不知道多少天了,之前有写了一部分规划路径的demo,昨天出于好奇新增了一个实时导航的功能,其实就是基于高德地图API实现的,为了方便以后项目快速集成,这也算是一个提前预热了哈哈哈

实时导航

开始集成

首先导入高德导航SDK

#import <AMapNaviKit/AMapNaviKit.h>

自定义新增需要用到的属性

@property (nonatomic, strong) AMapNaviDriveView * driveView; // 展示实时导航的界面
@property (nonatomic, strong) AMapNaviDriveManager *driveManager; // 管理器,负责实例获取导航路径信息
@property (nonatomic, strong) AMapNaviPoint *startPoint; // 路径起点
@property (nonatomic, strong) AMapNaviPoint *endPoint;  // 路径终点

懒加载导航界面和管理器,备着留后面用

// MARK: 初始化导航界面
- (void)initDriveView
{
    if (self.driveView == nil)
    {
        self.driveView = [[AMapNaviDriveView alloc] initWithFrame:self.view.bounds];
        self.driveView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
        [self.driveView setDelegate:self];
    }
}

- (void)initDriveManager
{
    if (!self.driveManager) {
        self.driveManager = [AMapNaviDriveManager sharedInstance];
        self.driveManager.delegate = self;
        [AMapNaviDriveManager sharedInstance].delegate = self;
    }
}

关键步骤来了

  • 第一行代码是用来开始计算起始点位置并计算路径信息
  • 第二行将管理器获取到的实时导航信息赋给我们的driveView,也就是导航界面,用来展示数据
    这个两个步骤处理的时机是在开始导航的时候做的,运行之后就进入了导航界面开始导航咯!
// 开始计算起始点路径
    [self.driveManager calculateDriveRouteWithStartPoints:@[self.startPoint] endPoints:@[self.endPoint] wayPoints:nil drivingStrategy:1];
    
    // 给driveView设置数据源,加载地图导航数据
    [self.driveManager addDataRepresentative:self.driveView];

在进入了导航界面默认会有一个退出按钮,一开始点击退出按钮没啥效果,是因为我们还没加处理,实现下面的代理方法,退出界面时要停止导航

- (void)driveViewCloseButtonClicked:(AMapNaviDriveView *)driveView {
    [[AMapNaviDriveManager sharedInstance] stopNavi];
    if (self.driveView) {
        [self.driveView removeFromSuperview];
    }
}

退出界面的时候需要把之前创建的代理和用于展示导航数据的DataRepresentative移除

- (void)dealloc
{
    [[AMapNaviDriveManager sharedInstance] stopNavi];
    [[AMapNaviDriveManager sharedInstance] removeDataRepresentative:self.driveView];
    [[AMapNaviDriveManager sharedInstance] setDelegate:nil];
    
    BOOL success = [AMapNaviDriveManager destroyInstance];
    NSLog(@"单例是否销毁成功 : %d",success);
    
}

到这里实时导航的功能就已经实现了,后期还会继续添加一些实用的功能😊

编辑日期:2020/3/3
github的代码需要手动下载一下pod,为了避免不必要的冲突,第三方库的代码没提交上去,谢谢!

如果有不清楚或者有误人子弟的地方,请立即提出来,谢谢。

Demo地址

https://github.com/miaoyuxuan/LineAnimation

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 有没有这样一本书,读了无数遍,清楚每一页的排版,但还是会在周末的午后或不开心时拿出来翻一翻。我想,或许《小王...
    谨兮阅读 708评论 0 1
  • Day48 5月5日 毋庸置疑,这个月我要“嗨”起来! 为嘛呢? 理由之一:我六月几乎三分之二的时间都在国外,回来...
    angela玲阅读 108评论 0 0
  • 今天,我还是浑浑噩噩的,还没有进入学习状态,明天争取多看点书,多听点听力。不能再刷知乎了,那简直是毒品啊,好的的时...
    苍白边缘阅读 233评论 0 0
  • 有时我们抓破脑袋都想不出一个文案,文案需要灵感,也需要刻意训练。分享一些句式,我们可以约会去刻意练习,代入句式。 ...
    康康的一只猫阅读 533评论 0 1