ios 高德地图运动轨迹绘制、运动距离计算
记录:项目开发之人员轨迹绘制
配置:需要倒入高德地图sdk,因为是实时获取用户位置信息需要在项目的Background Modes中勾选location updates
在项目info里面添加Privacy - Location Always Usage Description、Privacy - Location Always and When In Use Usage Description配置隐私权协议说明。
持续定位开启审核被拒事项:在审核的时候开启持续定位app可能会被拒,所以在配置隐私权协议的时候要描述你的定位在哪个功能用到,用来干什么说明清楚,然后在appstoreconnect里面描述中把开启持续定位的消耗说明一下,用户在可以看到这一块的描述,我是这么描述的【注意:本应用在使用巡查中需在后台持续进行用户信息定位,这可能使您的电池过快被消耗,在后台继续使用持续定位功能也会大大降低电池寿命,建议您在巡查的时候使用持续定位功能,巡查结束后本应用会自动关闭持续定位功能。】,防止被拒的发生最好是在附件里添加一个演示的视频。
准备好后开始代码模块
自定义MapLocationManager管理的类遵守AMapLocationManagerDelegate代理
实现AMapLocationManagerDelegate代理方法- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode;定位数据回调,在方法里实现数据的整理和距离的计算,具体如下
- (void)amapLocationManager:(AMapLocationManager*)managerdidUpdateLocation:(CLLocation*)locationreGeocode:(AMapLocationReGeocode*)reGeocode{
self.distance = KUser.run_distance.integerValue;
NSString*state =@"";
//因为做了开始、暂停、继续、结束的功能,使用对不同的状态进行了处理,其实这一块有些多余,因为在暂停和结束的时候已经调用了stopUpdatingLocation的方法,state的赋值是我用来区分不同的轨迹颜色用的标识,暂停的时候我会绘制黄色的轨迹路线,开始或者继续的状态下会绘制蓝色的轨迹路线
if (kStringIsEmpty(KUser.run_state)) {//未开始或者数据已结束上传
return;
}else{
if(KUser.run_state.integerValue==1||KUser.run_state.integerValue==3) {//开始、继续
state =@"1";
}else if(KUser.run_state.integerValue==2) {//暂停
state =@"2";
return;
}else{
return;
}
}
//模型里面是经纬度、时间,时间是用来计算运动时间的
YJRunLocationModel *locationModel = [[YJRunLocationModel alloc]init];
locationModel.location= location.coordinate;
locationModel.time= [NSDate date];
NSDictionary*current_dic =@{
@"longitude":[NSString stringWithFormat:@"%f",location.coordinate.longitude],
@"latitude":[NSString stringWithFormat:@"%f",location.coordinate.latitude],
@"time":locationModel.time,
@"state":state,//轨迹状态,区分绘制轨迹路线的颜色标识
};
if (kArrayIsEmpty([KUser getfectArray])) {
NSDictionary*dic =@{
@"longitude":[NSString stringWithFormat:@"%f",location.coordinate.longitude],
@"latitude":[NSString stringWithFormat:@"%f",location.coordinate.latitude],
@"time":locationModel.time,
@"state":state,
};
[KUser saveperfectArrayWith_obj:dic];//数据持久化,加入本地数组
}
_locationNumber++;//这个_locationNumber是用来计算经纬度之间的距离也就是行驶距离,下面有判断_locationNumber大于1才会计算两个经纬度之间的距离
if (_locationNumber > 1) {
NSDictionary*last_dic = [KUser getfectArray].lastObject;
[self distanceWithLocation:current_dic andLastButOneModel:last_dic];
}
}
//计算经纬度距离
-(void)distanceWithLocation:(NSDictionary *)current_dic andLastButOneModel:(NSDictionary *)last_dic {
CLLocationCoordinate2D current_location = CLLocationCoordinate2DMake([current_dic[@"latitude"]doubleValue], [current_dic[@"longitude"]doubleValue]);
MAMapPoint point1 =MAMapPointForCoordinate(current_location);
CLLocationCoordinate2D last_location =CLLocationCoordinate2DMake([last_dic[@"latitude"]doubleValue], [last_dic[@"longitude"]doubleValue]);
MAMapPoint point2 =MAMapPointForCoordinate(last_location);
//2.计算距离
CLLocationDistance newdistance =MAMetersBetweenMapPoints(point1,point2);
//估算两者之间的时间差,单位 秒
NSTimeInterval secondsBetweenDates= [current_dic[@"time"]timeIntervalSinceDate:last_dic[@"time"]];
//maxSpeed人的最高时速和运动时速比较,我做的操作是超出了人类的极限就不把当前的经纬度坐标加到本地数组里
if((float)newdistance/secondsBetweenDates <=self.maxSpeed) {
NSDictionary*dic =@{
@"longitude":current_dic[@"longitude"],
@"latitude":current_dic[@"latitude"],
@"time":current_dic[@"time"],
@"state":current_dic[@"state"],
};
[KUser saveperfectArrayWith_obj:dic];
if([dic[@"state"]integerValue]==1) {//开始进行中才算距离,暂停不需要计算距离
}
self.distance=self.distance+ newdistance;
KUser.run_distance = [NSString stringWithFormat:@"%ld",(long)self.distance];
NSString*text = [NSStringstringWithFormat:@"%ld",(long)self.distance];
KUser.run_distance= text;
if (self.bk_drawRunLineActionBlock) {
self.bk_drawRunLineActionBlock(self.distance);
}
}
}
工具类准备完毕后,下面是地图轨迹的绘制代码
首先遵守MAMapViewDelegate方法
#pragma mark- 懒加载
-(MAMapView *)mapView {
if(_mapView==nil) {
_mapView = [[MAMapView alloc] initWithFrame:self.view.bounds];
_mapView.desiredAccuracy = kCLLocationAccuracyBest;
_mapView.distanceFilter = 1.0f;
_mapView.showsUserLocation = YES;
_mapView.userTrackingMode = MAUserTrackingModeFollow;//地图跟着位置移动
_mapView.zoomLevel=16;
_mapView.maxZoomLevel=18;
_mapView.showsScale=NO;//不显示比例尺
_mapView.showsCompass=NO;//不显示罗盘
_mapView.delegate =self;
MAUserLocationRepresentation *r = [[MAUserLocationRepresentation alloc] init];
r.showsAccuracyRing = NO;///精度圈是否显示,默认YES
r.showsHeadingIndicator = normal;
[_mapView updateUserLocationRepresentation:r];
}
return _mapView;
}
//绘制折线样式
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id <MAOverlay>)overlay {
if([overlay isKindOfClass:[MAMultiPolyline class]]) {
// MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:overlay];
// polylineRenderer.strokeColor = self.lineColor;
// polylineRenderer.lineWidth = self.lineWidth;
// return polylineRenderer;
MAMultiTexturePolylineRenderer * polylineRenderer = [[MAMultiTexturePolylineRenderer alloc] initWithMultiPolyline:overlay];
polylineRenderer.lineWidth=16;
//drawLineColors每个坐标点的颜色数据,我这里用的是图片所以用到的是strokeTextureImages属性
polylineRenderer.strokeTextureImages=self.drawLineColors;
return polylineRenderer;
}
return nil;
}
//绘制开始位置大头针
- (void)drawStartRunPointAction:(YJRunLocationModel *)runModel {
if (_mapView.userLocation.location != nil) {//
}
MAPointAnnotation *pointAnnotation = [[MAPointAnnotation alloc] init];
pointAnnotation.coordinate= runModel.location;
[_mapView addAnnotation:pointAnnotation];
}
// 定义大头针样式
-(MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id <MAAnnotation>)annotation {
if([annotation isKindOfClass:[MAPointAnnotation class]]){
MAAnnotationView*annotationView = (MAAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:@"startLocation"];
if(annotationView ==nil) {
annotationView = [[MAAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"startLocation"];
}
annotationView.image=THEME_IMAGE(@"r_run_star");//
annotationView.centerOffset=CGPointMake(0,0);
returnannotationView;
}else{
}
return nil;
}
//接下是在地图上绘制轨迹路线的方法,这个方法是在位置信息发生改变的时候回调中使用
- (void)drawRunLineAction {
YJRunLocationModel *endLocation = [YJRunLocationModel modelWithJSON:[KUser getfectArray][0]];
endLocation.location=CLLocationCoordinate2DMake(endLocation.latitude, endLocation.longitude);
NSMutableArray *arr = [NSMutableArray array];
for(inti =0; i < [KUsergetfectArray].count; i++) {
YJRunLocationModel *newlocation = [YJRunLocationModel modelWithJSON:[KUser getfectArray][i]];
newlocation.location=CLLocationCoordinate2DMake(newlocation.latitude, newlocation.longitude);
MAMapPointpoint1 =MAMapPointForCoordinate(newlocation.location);
MAMapPointpoint2 =MAMapPointForCoordinate(endLocation.location);
//2.计算距离
CLLocationDistancenewDistance =MAMetersBetweenMapPoints(point1,point2);
endLocation = newlocation;
[arr addObject:newlocation];
}
NSMutableArray*drawStyleIndexes = [NSMutableArr ayarray];
self.drawLineColors = [NSMutableArray array];
CLLocationCoordinate2D commonPolylineCoords[arr.count];
for(inti =0; i < arr.count; i++) {
YJRunLocationModel*locationModel = arr[i];
commonPolylineCoords[i] = locationModel.location;
NSDictionary*dic = [KUser getfectArray][i];
[drawStyleIndexes addObject:@(i)];
if([dic[@"state"]integerValue]==2) {
UIImage*yellow =THEME_IMAGE(@"custtexture_yellow");
[self.drawLineColors addObject:yellow];
}else if([dic[@"state"]integerValue]==1) {
UIImage*blue =THEME_IMAGE(@"custtexture_blue");
[self.drawLineColors addObject:blue];
}
}
[self.mapView removeOverlay:self.polyline];
self.polyline= [MAMultiPolyline polylineWithCoordinates:commonPolylineCoords count:arr.count drawStyleIndexes:drawStyleIndexes];
[self.mapView addOverlay:self.polyline];
}
end 🔚