Demo集成初衷
本人上手的第一个项目就是基于高德地图,对于地图开发兴趣浓厚,2018年初步了解了高德地图的sdk,遇到了很多不懂的,也慢慢的研究了出来,最近在回顾的时候发觉还有好多地图的功能自己还不熟悉,决定再次深入研究。
本文研究内容
一.关键字搜索地理位置
二.路径规划
三.小车轨迹移动动画,车辆的暂停,继续运动
四.实时导航
正文
关键字搜索地理位置
首先导入需要用到的库
#import
#import
#import
遵循协议
在控制器中将地图添加进去,先让地图显示出来
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)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)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
自定义新增需要用到的属性
@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