// // TrackMapView.m // LekangGuard // // Created by ecell on 2022/12/15. // #import "TrackMapView.h" #import "TracingPoint.h" #import "CustomAnnotationView.h" #import "Util.h" #import "MKPointAnnotation+NewTemp.h" //高德 #import #import #define kAnimationDuration 3 #define kSpeed 50 // 每秒多少像素 //关键帧旋转动画 #define RotationAnimationKey @"transform.rotation.z" //关键帧位移动画 #define PositionAnimationKey @"position" //关键帧划线动画 #define StrokeEndAnimationKey @"strokeEnd" @interface TrackMapView () @property (nonatomic ,strong) UIView *topView; @property(strong ,nonatomic) MKMapView *mapView; //动画持续的时间 (不超过5秒) 时速 每秒 320 @property(nonatomic,assign) NSTimeInterval durationTime; // 路线动画 @property(nonatomic,strong) CAAnimation *shapeLayerAnimation; // 头部光点动画 @property(nonatomic,strong) CAKeyframeAnimation *headLayerAnimation; @property(nonatomic,assign) NSInteger currentIndex ; //路径点的指针数组 @property(nonatomic,assign) CGPoint *pathPoints; //路径点的指针数组 @property(nonatomic,strong) NSMutableArray *pathPointsModels; // angele数组 每个点的指向 @property(nonatomic,strong) NSMutableArray *angeleValues; @property(nonatomic,assign) double SumJuli; @property(nonatomic,strong) MKPolyline *routeLine; @property(nonatomic,strong) MKPolylineRenderer *routeLineView; @property(nonatomic,strong) NSMutableArray* pointAnnotationArr; // @property(nonatomic,strong) NSArray *animations; @property(nonatomic,strong) NSArray *juliArr; /** 轨迹回放的layer */ @property(nonatomic,strong) CAShapeLayer * shapeLayer; /** 头部的光点 */ //@property(nonatomic,strong) CAShapeLayer * headView; @property(nonatomic,strong) UIImageView * headView; @property(nonatomic,strong) NSArray* beziePaths; /** 轨迹回放图层 */ @property(nonatomic,strong) UIView *trackView; @property (nonatomic, strong) AMapSearchAPI *searchAPI; /// @property (nonatomic ,weak) UIButton *startAndStopBtn; @property (nonatomic ,assign) UIImageView *mapImg; @property (nonatomic ,weak) UILabel *locationTypeLabel; @property (nonatomic ,weak) UILabel *locationAddressLabel; @end @implementation TrackMapView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.frame = frame; self.backgroundColor = KKWhiteColorColor; [self viewDidLoads]; } return self; } - (UIView *)topView { if (!_topView) { _topView = [UIView new]; _topView.hidden = YES; _topView.backgroundColor = KKWhiteColorColor; _topView.frame = CGRectMake(0, -Adapted(55), SCREEN_WIDTH, Adapted(55)); UIImageView *mapImg = [UICommon ui_imageView:CGRectZero fileName:@"icon_base_station"]; self.mapImg = mapImg; [_topView addSubview:mapImg]; [mapImg mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(_topView).offset(15); make.bottom.equalTo(_topView.mas_centerY); make.size.mas_equalTo(CGSizeMake(AdaptedHeight(self.mapImg.image.size.width), AdaptedHeight(self.mapImg.image.size.height))); }]; UILabel *locationTypeLabel = [UICommon ui_label:CGRectZero lines:0 align:NSTextAlignmentCenter font:FontADA_(11) textColor:KKGrey121 text:@"LBS" Radius:0]; self.locationTypeLabel = locationTypeLabel; [_topView addSubview:locationTypeLabel]; [locationTypeLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(mapImg); make.top.equalTo(mapImg.mas_bottom).offset(3); }]; UILabel *locationAddressLabel = [UICommon ui_label:CGRectZero lines:0 align:NSTextAlignmentLeft font:FontADA_(13) textColor:KKTextBlackColor text:@"" Radius:0]; self.locationAddressLabel = locationAddressLabel; [_topView addSubview:locationAddressLabel]; [locationAddressLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(_topView); make.left.equalTo(mapImg.mas_right).offset(10); make.right.equalTo(_topView.mas_right).inset(15); }]; } return _topView; } - (void)topViewShowAndHidden:(NSInteger)isShow { self.topView.hidden = isShow == 1 ? NO : YES; [UIView animateWithDuration:0.5 animations:^{ self.topView.frame = CGRectMake(0,isShow == 1 ? 0 : -Adapted(55), SCREEN_WIDTH, Adapted(55)); } completion:^(BOOL finished) { }]; } - (void)viewDidLoads { [self addSubview:self.mapView]; [self addSubview:self.topView]; self.searchAPI = [[AMapSearchAPI alloc] init]; self.searchAPI.delegate = self; UIButton *startAndStopBtn = [UICommon ui_buttonSimple:CGRectZero font:Font_(0) normalColor:KKWhiteColorColor normalText:@"" click:^(UIButton *btn) { btn.selected = !btn.selected; [self startAndStopBtnAction:btn]; }]; [startAndStopBtn setImage:ImageName_(@"icon_start") forState:UIControlStateNormal]; [startAndStopBtn setImage:ImageName_(@"icon_stop") forState:UIControlStateSelected]; startAndStopBtn.backgroundColor = KKWhiteColorColor; startAndStopBtn.layer.cornerRadius = 5; startAndStopBtn.layer.masksToBounds = YES; self.startAndStopBtn = startAndStopBtn; [self addSubview:startAndStopBtn]; [startAndStopBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(self.mas_right).inset(20); make.top.equalTo(self).offset(Adapted(55)+30); make.size.mas_equalTo(CGSizeMake(Adapted(48), Adapted(48))); }]; } //MARK: 重新加载地图轨迹数据 - (void)loadWithInfoTrack:(NSArray *)mapPoints { self.startAndStopBtn.selected = NO; [self startAndStopBtnAction:self.startAndStopBtn]; [self.mapView removeAnnotations:self.pointAnnotationArr]; [self.mapView removeOverlay:self.routeLine]; self.trackView = nil; self.routeLine = nil; self.routeLineView = nil; self.pointAnnotationArr = nil; if(self.headView){ [self.headView.layer removeAllAnimations]; self.headView = nil; } if(self.pathPoints) { free(self.pathPoints); self.pathPoints = nil; } [self addLocate:mapPoints]; if(mapPoints.count > 1) { self.startAndStopBtn.selected = YES; [self startAndStopBtnAction:self.startAndStopBtn]; } //默认选中 起点 CustomAnnotationView *tempView = [CustomAnnotationView new]; tempView.annotation = self.pointAnnotationArr.lastObject; [self mapView:self.mapView didSelectAnnotationView:tempView]; } -(void)startAndStopBtnAction:(UIButton *)sender { if(sender.isSelected) { [self.mapView removeAnnotations:self.pointAnnotationArr]; [self.mapView removeOverlay:self.routeLine]; self.currentIndex = 0; //经纬度的区域坐标 if(self.routeLine) { MKMapRect mapShowRect = [self.routeLine boundingMapRect]; NSLog(@"停止按钮:mapShowRect X: %f Y:%f Width: %f, Height: %f", mapShowRect.origin.x,mapShowRect.origin.y,mapShowRect.size.width,mapShowRect.size.height); //显示区域 [self.mapView setVisibleMapRect:mapShowRect edgePadding:UIEdgeInsetsMake(50, 50, 50, 50) animated:NO]; } [self initShapeLayerWithPath:[self pathForPoints:self.pathPoints count:self.pointAnnotationArr.count]]; } else { // [self.mapView removeAnnotations:self.pointAnnotationArr]; // [self.mapView removeOverlay:self.routeLine]; [self.trackView removeFromSuperview]; self.trackView = nil; self.currentIndex = 0; [self.mapView addAnnotations:self.pointAnnotationArr]; } [sender setSelected:!sender.isSelected]; self.mapView.userInteractionEnabled = sender.isSelected; } #pragma mark - 构造shapeLayer - (void)initShapeLayerWithPath:(CGPathRef)path { if(_shapeLayer) { [self.shapeLayer removeAllAnimations]; [self.shapeLayer removeFromSuperlayer]; [self.headView.layer removeAllAnimations]; [self.headView.layer removeFromSuperlayer]; [self.headView removeFromSuperview]; self.shapeLayer = nil; self.headView = nil; } self.shapeLayer = [[CAShapeLayer alloc] init]; self.shapeLayer.frame = self.trackView.bounds; self.shapeLayer.frame = self.mapView.bounds; self.shapeLayer.strokeColor = KKMainColor.CGColor; self.shapeLayer.fillColor = [UIColor clearColor].CGColor; self.shapeLayer.lineJoin = kCALineJoinRound; self.shapeLayer.lineCap = kCALineCapRound; self.shapeLayer.lineWidth = 3; self.shapeLayer.path = path; self.shapeLayer.lineDashPhase = 10; NSArray *arr = @[@(10),@(10)]; self.shapeLayer.lineDashPattern = arr; self.headView = [[UIImageView alloc] init]; self.headView.frame = CGRectMake(-20, -20, 10, 10); self.headView.backgroundColor = [UIColor whiteColor]; self.headView.layer.cornerRadius = 5; self.headView.layer.masksToBounds = YES; // self.headView.image = [UIImage imageNamed:@"icon_orientierungspunkt"]; if(self.angeleValues.count > 1) { self.headView.transform = CGAffineTransformMakeRotation(self.angeleValues[self.angeleValues.count-1].doubleValue); } [self.trackView.layer addSublayer:self.shapeLayer]; [self.trackView.layer addSublayer: self.headView.layer]; self.shapeLayerAnimation = [self constructShapeLayerAnimation]; self.shapeLayerAnimation.delegate = self; self.shapeLayerAnimation.removedOnCompletion = NO; self.shapeLayerAnimation.fillMode = kCAFillModeForwards; [self.shapeLayer addAnimation:self.shapeLayerAnimation forKey:@"shape"]; self.animations = [self constructHeadLayerAnimationWithBeziePaths:self.beziePaths]; if(self.animations.count != 0) { self.headLayerAnimation = self.animations[self.currentIndex]; self.headLayerAnimation.removedOnCompletion = NO; self.headLayerAnimation.delegate = self; [self.headView.layer addAnimation:self.headLayerAnimation forKey:[NSString stringWithFormat:@"headPosition%ld",(long)self.currentIndex]]; // [self.mapView addAnnotation:self.pointAnnotationArr.lastObject]; [self addTrackViewPoint:self.pathPoints[0] Type:0 Angle:0]; } } //MARK: 动画的代理方法 ----------CAAnimationDelegate------------ -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { if([anim isKindOfClass:[CABasicAnimation class]]) { if(self.routeLine) { [self.mapView addOverlay:self.routeLine]; } } if([anim isKindOfClass:[CAKeyframeAnimation class]]) { self.currentIndex++; if (self.currentIndex = self.animations.count){ self.currentIndex = 0; if(self.pathPoints){ [self addTrackViewPoint:self.pathPoints[self.pointAnnotationArr.count-1] Type:2 Angle:0]; [self.headView.layer removeFromSuperlayer]; if(!self.startAndStopBtn.isSelected) { [self startAndStopBtnAction:self.startAndStopBtn]; } } return; } CAKeyframeAnimation *nextAnim = self.animations[self.currentIndex]; nextAnim.removedOnCompletion = NO; nextAnim.delegate = self; // [self.headView addAnimation:nextAnim forKey:[NSString stringWithFormat:@"headPosition%d",currentIndex]]; [self.headView.layer addAnimation:nextAnim forKey:@"headPosition"]; if(self.pathPoints){ CGPoint currentPoint = self.pathPoints[self.currentIndex]; if (self.currentIndex == 0){ //第一 [self addTrackViewPoint:currentPoint Type:0 Angle:0]; double angle = self.angeleValues[self.angeleValues.count-1].doubleValue; self.headView.transform = CGAffineTransformMakeRotation(angle); }else if(self.currentIndex == self.pointAnnotationArr.count-1){ //最后一个 [self addTrackViewPoint:currentPoint Type:2 Angle:0]; }else{ NSInteger tempIndex = self.angeleValues.count-self.currentIndex-1; if(tempIndex < 0){ tempIndex = 0; } double angle = self.angeleValues[tempIndex].doubleValue; // if(self.currentIndex == 1){ // self.headView.transform = CGAffineTransformMakeRotation(angle); // } [self addTrackViewPoint:currentPoint Type:1 Angle:angle ]; self.headView.transform = CGAffineTransformMakeRotation(angle); } } } } //MARK: 添加 在TrackView 上的点 /** 添加 在TrackView 上的点 @param centerPoint 点的坐标 @param type 类型 起点 0 平常 1 终点 2 @param angle 图标旋转的 弧度 */ -(void)addTrackViewPoint:(CGPoint)centerPoint Type:(int)type Angle:(double)angle{ if(!_trackView){ return; } CGFloat Width = 12; CGFloat height = 12; __block UIImageView *view = [UIImageView new]; view.contentMode = UIViewContentModeScaleAspectFit; switch (type) { case 0: view.frame = CGRectMake(0, 0, 30, 30); view.image = [UIImage imageNamed:@"icon_start_point"]; view.center = CGPointMake(centerPoint.x, centerPoint.y-15); break; case 1: view.frame = CGRectMake(0, 0, Width,height); view.image = [UIImage imageNamed:@"icon_orientierungspunkt"]; // xLog(@"radian: %f", angle); view.transform = CGAffineTransformRotate(view.transform, angle); view.center = centerPoint; break; case 2: view.frame = CGRectMake(0, 0, 30, 30); view.image = [UIImage imageNamed:@"icon_end_point_1"]; view.center = CGPointMake(centerPoint.x, centerPoint.y-15); break; default: break; } [_trackView addSubview:view]; //自定义动画 // view.transform = CGAffineTransformScale(view.transform, 0.5, 0.5); // // 弹簧动画,参数分别为:时长,延时,弹性(越小弹性越大),初始速度 // [UIView animateWithDuration:1 delay:0 usingSpringWithDamping:0.3 initialSpringVelocity:0.3 options:UIViewAnimationOptionLayoutSubviews animations:^{ // //因为先缩放了所以得 2倍 0.5*2 = 1 // view.transform = CGAffineTransformScale(view.transform, 2, 2); // } completion:^(BOOL finished) { // // }]; } #pragma mark - 经纬度转屏幕坐标, 调用者负责释放内存! - (CGPoint *)pointsForCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count{ if (coordinates == NULL || count <= 1) { return NULL; } /* 申请屏幕坐标存储空间. */ CGPoint *points = (CGPoint *)malloc(count * sizeof(CGPoint)); /* 经纬度转换为屏幕坐标. */ for (int i = 0; i < count; i++) { points[i] = [self.mapView convertCoordinate:coordinates[i] toPointToView:self.mapView]; } return points; } #pragma mark - 构建path, 调用者负责释放内存! - (CGPathRef)pathForPoints:(CGPoint *)points count:(NSUInteger)count{ if (points == NULL || count <= 1){ return NULL; } UIBezierPath *layerPathBezier = [UIBezierPath bezierPath]; [layerPathBezier moveToPoint:points[0]]; //贝塞尔路线数组 NSMutableArray *mbeziePaths = [NSMutableArray array]; //上一个点 CGPoint lastPoint = points[0]; double sumJuli = 0; NSMutableArray *juliArr = [NSMutableArray array]; for (int i = 1 ; i < count; i++) { UIBezierPath *beziePath = [UIBezierPath bezierPath]; [beziePath moveToPoint:lastPoint]; [beziePath addLineToPoint:points[i]]; [layerPathBezier addLineToPoint:points[i]]; CGPoint nowPiont = points[i]; CGFloat xDist = lastPoint.x - nowPiont.x; CGFloat yDist = lastPoint.y - nowPiont.y; double juli = sqrt((xDist*xDist)+(yDist*yDist)); [juliArr addObject:@(juli)]; //计算总的距离(相对在屏幕上的距离) sumJuli += juli; lastPoint = points[i]; [mbeziePaths addObject:beziePath]; } self.juliArr = [juliArr copy]; self.SumJuli = sumJuli; self.durationTime = sumJuli/(kSpeed); //每秒 320/2 dp 距离 // if(self.durationTime > 5.00){ // self.durationTime = 5.00; // } self.beziePaths = [mbeziePaths copy]; return layerPathBezier.CGPath; } #pragma mark - 构建shapeLayer的basicAnimation - (CAAnimation *)constructShapeLayerAnimation{ CABasicAnimation *theStrokeAnimation = [CABasicAnimation animationWithKeyPath:StrokeEndAnimationKey]; //画线 theStrokeAnimation.duration = self.durationTime; theStrokeAnimation.fromValue = @0.f; theStrokeAnimation.toValue = @1.f; theStrokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; return theStrokeAnimation; } #pragma mark - 构建动画轨迹头部发光点 关键帧动画 - (NSArray *)constructHeadLayerAnimationWithBeziePaths:(NSArray*)beziePaths{ if(self.juliArr.count != beziePaths.count){ return [NSArray array]; } NSMutableArray *arr = [NSMutableArray array]; CAAnimationGroup *group = [CAAnimationGroup animation]; for (int i=0; i*)arr { kWeakSelf(self) NSMutableArray *pointArr = [NSMutableArray array]; self.pathPointsModels = [NSMutableArray array]; self.angeleValues = [NSMutableArray array]; TracingPoint * firstTp = [[TracingPoint alloc] init]; TrackInfoModel *firstLocate = arr.firstObject; firstTp.coordinate = CLLocationCoordinate2DMake([firstLocate.lat doubleValue], [firstLocate.lon doubleValue]); // firstTp.course = [self.pathPointsModels firstObject].course; [self.pathPointsModels addObject:firstTp]; [self.angeleValues addObject:@(0)]; for (int i = 1; i 2) TrackInfoModel *tempLocate2 = arr[i-1]; CLLocationCoordinate2D tempCoordinate2 = CLLocationCoordinate2DMake([tempLocate2.lat doubleValue], [tempLocate2.lon doubleValue]); TracingPoint * tp = [[TracingPoint alloc] init]; //此点的坐标 tp.coordinate = tempCoordinate; //此点相对于上个点的偏移角 tp.course = [Util calculateCourseFromCoordinate:tempCoordinate to:tempCoordinate2]; // 角度转换 double radian = [Util fixNewDirection: tp.course basedOnOldDirection:0]; //计算弧度 角度*弧度值 DegToRad [self.angeleValues addObject:@(radian*DegToRad)]; [self.pathPointsModels addObject:tp]; } // self.angeleValues = [NSMutableArray array]; // NSArray *tempArr = [self.pathPointsModels copy]; // for (int i = 0; i < tempArr.count; i++) { // TracingPoint *tp = tempArr[i]; // //angle // double currDir = [Util fixNewDirection:tp.course basedOnOldDirection:0]; // //DegToRad 1弧度对应多少度 // [self.angeleValues addObject:@(currDir * DegToRad)]; // } [arr enumerateObjectsUsingBlock:^(TrackInfoModel * _Nonnull locate, NSUInteger idx, BOOL * _Nonnull stop) { MKPointAnnotation *pointAnnotation = [[MKPointAnnotation alloc] init]; pointAnnotation.tempLocate = locate; pointAnnotation.tracingPoint = self.pathPointsModels[idx]; // xLog(@"idx: %d, tp.course:%f ", idx, pointAnnotation.tracingPoint.course); CLLocationCoordinate2D tempCoordinate = CLLocationCoordinate2DMake([locate.lat doubleValue], [locate.lon doubleValue]); pointAnnotation.coordinate = tempCoordinate; NSDate *date = [NSDate dateWithTimeIntervalSince1970:[locate.updateTime doubleValue]]; NSString *dateStr = [UICommon getDateFormatWithStr:@"M月d日 HH:mm" date:date]; if (locate.locationType) { pointAnnotation.title = [NSString stringWithFormat:@"定位类型:%@ %@",locate.locationType,dateStr]; }else{ pointAnnotation.title = [NSString stringWithFormat:@"%@",dateStr]; } pointAnnotation.subtitle = locate.addr; CLLocation * pointLocation = [[CLLocation alloc] initWithLatitude:[locate.lat doubleValue] longitude:[locate.lon doubleValue]]; [pointArr addObject:pointLocation]; // [weakSelf setMapZoom:pointAnnotation.coordinate]; [weakself.pointAnnotationArr addObject:pointAnnotation]; // [weakSelf.mapView addAnnotation:pointAnnotation]; }]; if(arr.count > 1){ [self drawLineWithLocationArray:[pointArr copy]]; [self.startAndStopBtn setHidden:NO]; }else{ [self.startAndStopBtn setHidden:YES]; if(self.pointAnnotationArr && self.pointAnnotationArr.count > 0){ [self.mapView addAnnotations:self.pointAnnotationArr]; self.mapView.userInteractionEnabled = YES; [self.mapView showAnnotations:self.pointAnnotationArr animated:YES]; [self.mapView selectAnnotation:self.pointAnnotationArr[0] animated:YES]; } } } #pragma mark - 画线 - (void)drawLineWithLocationArray:(NSArray *)locationArray { NSInteger pointCount = [locationArray count]; CLLocationCoordinate2D *coordinateArray = (CLLocationCoordinate2D *)malloc(pointCount * sizeof(CLLocationCoordinate2D)); for (int i = 0; i < pointCount; ++i) { CLLocation *location = [locationArray objectAtIndex:i]; coordinateArray[(pointCount-1)-i] = [location coordinate]; } self.routeLine = [MKPolyline polylineWithCoordinates:coordinateArray count:pointCount]; //经纬度的区域坐标 MKMapRect mapShowRect = [self.routeLine boundingMapRect]; NSLog(@"mapShowRect X: %f Y:%f Width: %f, Height: %f", mapShowRect.origin.x,mapShowRect.origin.y,mapShowRect.size.width,mapShowRect.size.height); //显示区域 [self.mapView setVisibleMapRect:mapShowRect edgePadding:UIEdgeInsetsMake(50, 50, 50, 50) animated:NO]; //把路径点变成在 屏幕上的坐标点 self.pathPoints = [self pointsForCoordinates:coordinateArray count:pointCount]; free(coordinateArray); coordinateArray = NULL; } #pragma mark - 地图控件代理方法 #pragma mark 显示大头针时调用,注意方法中的annotation参数是即将显示的大头针对象 -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{ //由于当前位置的标注也是一个大头针,所以此时需要判断,此代理方法返回nil使用默认大头针视图 static NSString *key1=@"AnnotationKey1"; CustomAnnotationView *annotationView = (CustomAnnotationView*)[_mapView dequeueReusableAnnotationViewWithIdentifier:key1]; MKPointAnnotation *pointAnnotation = (MKPointAnnotation*)annotation; //如果缓存池中不存在则新建 if (!annotationView) { annotationView=[[CustomAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:key1]; annotationView.canShowCallout=NO;//不允许交互点击 }else{ //重新设置此类大头针视图的大头针模型(因为有可能是从缓存池中取出来的,位置是放到缓存池时的位置) annotationView.annotation = annotation; } if([annotation isEqual:self.pointAnnotationArr.firstObject]&&self.pointAnnotationArr.count>1){ //修改大头针视图 设置终点 [annotationView setImageWithString:@"icon_end_point_1"]; //设置大小 annotationView.frame = CGRectMake(0, 0, 30, 30); //设置中心偏移量 annotationView.centerOffset = CGPointMake(0, -15); annotationView.calloutOffset=CGPointMake(0, 1);//定义详情视图偏移量 return annotationView; } if([annotation isEqual:self.pointAnnotationArr.lastObject]){ //修改大头针视图 设置起点 [annotationView setImageWithString:@"icon_start_point"]; //设置大小 annotationView.frame = CGRectMake(0, 0, 30, 30); //设置中心偏移量 annotationView.centerOffset = CGPointMake(0, -15); annotationView.calloutOffset=CGPointMake(0, 1);//定义详情视图偏移量 return annotationView; } [annotationView setImageWithString:@"icon_orientierungspunkt"]; double radian = [Util fixNewDirection:pointAnnotation.tracingPoint.course basedOnOldDirection:0]; // xLog(@"radian %f", radian*DegToRad); [annotationView setRadian:radian*DegToRad]; //设置大小 annotationView.frame = CGRectMake(0, 0, 12, 12); //设置中心偏移量 annotationView.centerOffset = CGPointMake(3, -3); annotationView.calloutOffset=CGPointMake(0, 0);//定义详情视图偏移量 return annotationView; } //MARK: 点击地图 中的 标点 触发的方法 -(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view { if([view isKindOfClass:[CustomAnnotationView class]]) { if([view.annotation isKindOfClass:[MKPointAnnotation class]]) { MKPointAnnotation *pointAnnotation = (MKPointAnnotation*)view.annotation; self.curLocate = pointAnnotation.tempLocate; if(!self.curLocate) { return; } }else{ return; } //自定义动画 view.transform = CGAffineTransformScale(view.transform, 0.5, 0.5); // 弹簧动画,参数分别为:时长,延时,弹性(越小弹性越大),初始速度 [UIView animateWithDuration:1 delay:0 usingSpringWithDamping:0.3 initialSpringVelocity:0.3 options:UIViewAnimationOptionLayoutSubviews animations:^{ view.transform = CGAffineTransformScale(view.transform, 2, 2); } completion:^(BOOL finished) { }]; // 设备点 self.locationTypeLabel.text = self.curLocate.locationType; if ([self.curLocate.locationType isEqualToString:@"LBS"]) self.mapImg.image = ImageName_(@"icon_home_base_station"); else if ([self.curLocate.locationType isEqualToString:@"GPS"]) self.mapImg.image = ImageName_(@"icon_histroy_g"); else if ([self.curLocate.locationType isEqualToString:@"WIFI"]) self.mapImg.image = ImageName_(@"icon_home_wifi"); [self.mapImg mas_remakeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.topView).offset(15); make.bottom.equalTo(self.topView.mas_centerY); make.size.mas_equalTo(CGSizeMake(AdaptedHeight(self.mapImg.image.size.width), AdaptedHeight(self.mapImg.image.size.height))); }]; if(self.curLocate.addr.length > 0){ NSString *dateStr = self.curLocate.updateTime; NSMutableAttributedString *att = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ %@",self.curLocate.addr,self.curLocate.updateTime]]; [att addAttribute:NSForegroundColorAttributeName value:KKMainColor range:NSMakeRange(att.length-dateStr.length,dateStr.length)]; self.locationAddressLabel.attributedText = att; }else{ AMapReGeocodeSearchRequest *regeo = [[AMapReGeocodeSearchRequest alloc] init]; regeo.location = [AMapGeoPoint locationWithLatitude:[self.curLocate.lat floatValue] longitude:[self.curLocate.lon floatValue]]; [self.searchAPI AMapReGoecodeSearch:regeo]; } } } - (MKOverlayRenderer *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay { if ([overlay isKindOfClass:[MKCircle class]]) { MKCircleRenderer *circle = [[MKCircleRenderer alloc] initWithOverlay:overlay]; circle.strokeColor = [UIColor clearColor]; circle.fillColor = [[UIColor blueColor] colorWithAlphaComponent:0.1]; // circle.lineWidth = 1; return circle; } if (overlay == self.routeLine) { if(nil == self.routeLineView) { self.routeLineView = [[MKPolylineRenderer alloc] initWithPolyline:self.routeLine] ; //虚线=== //self.routeLineView.lineDashPhase = 10; //NSArray* array = [NSArray arrayWithObjects:[NSNumber numberWithInt:15] , [NSNumber numberWithInt:15],nil]; // 2 //self.routeLineView.lineDashPattern = array; // 3 //==== self.routeLineView.fillColor = KKMainColor; self.routeLineView.strokeColor = KKMainColor; self.routeLineView.lineWidth = 4; } return self.routeLineView; } return nil; } #pragma mark ====高德地图位置解析回调==== -(void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response { if (response.regeocode != nil) { NSString *name = response.regeocode.formattedAddress; NSString *dateStr = self.curLocate.updateTime; NSMutableAttributedString *att = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ %@",name,dateStr]]; [att addAttribute:NSForegroundColorAttributeName value:KKMainColor range:NSMakeRange(att.length-dateStr.length,dateStr.length)]; self.locationAddressLabel.attributedText = att; } } - (void)didReceiveMemoryWarning { //[super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. switch (self.mapView.mapType) { case MKMapTypeHybrid: { self.mapView.mapType = MKMapTypeStandard; } break; case MKMapTypeStandard: { self.mapView.mapType = MKMapTypeHybrid; } break; default: break; } self.mapView.mapType = MKMapTypeStandard; } -(void)dealloc{ NSLog(@"销毁 历史轨迹展示页面"); } - (MKMapView *)mapView { if (!_mapView) { CGFloat yy = iPhoneX_NavHeight+Adapted(50)+0.5; _mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-yy)]; MKCoordinateSpan span = MKCoordinateSpanMake(0.021251, 0.016093); CLLocationCoordinate2D center = self.mapView.region.center; [_mapView setRegion:MKCoordinateRegionMake(center, span) animated:YES]; _mapView.rotateEnabled = NO; _mapView.userInteractionEnabled = NO; _mapView.delegate = self; } return _mapView; } -(NSMutableArray *)pointAnnotationArr { if(!_pointAnnotationArr){ _pointAnnotationArr = [NSMutableArray array]; } return _pointAnnotationArr; } -(UIView *)trackView { if(!_trackView){ _trackView = [[UIView alloc] initWithFrame: self.mapView.bounds]; _trackView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.1]; [self.mapView addSubview:_trackView]; } return _trackView; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end