需求场景:快递物流相关APP中,如快递、送餐,可以让快递车Marker的车头,在途经点始终指向目的地,如下图所示:
使用技术:腾讯地图iOS SDK,点标记和绘制线
核心点:
- 操作QPointAnnotation的坐标
- 从mapView中获取途经点QPointAnnotation的坐标
- 通过三角函数计算途经点坐标与终点坐标的角度
- 操作QAnnotationView的transform属性
代码示例如下:
-
示例展示福州送至北京,途径西安、西宁、济南、太原、天津,先将这几个点的maker添加到地图中:
// 福州 locations[0] = CLLocationCoordinate2DMake(26.101797,119.415539); // 西安 locations[1] = CLLocationCoordinate2DMake(34.475422,109.0005); // 西宁 locations[2] = CLLocationCoordinate2DMake(36.69099,101.749523); // 济南 locations[3] = CLLocationCoordinate2DMake(36.761434,117.174328); // 太原 locations[4] = CLLocationCoordinate2DMake(37.949064,112.56007); // 天津 locations[5] = CLLocationCoordinate2DMake(39.117802,117.174328); // 北京 locations[6] = CLLocationCoordinate2DMake(39.897614,116.383312); // 福州 QPointAnnotation *nnAnnotation = [[QPointAnnotation alloc] init]; nnAnnotation.coordinate = locations[0]; [self.mapView addAnnotation:nnAnnotation]; ....
-
添加小车marker,以福州为起始点:
_carAnnotation = [[QPointAnnotation alloc] init]; _carAnnotation.coordinate = locations[0]; // 指定userData自定义数据,用于判断marker的类型 _carAnnotation.userData = @"car"; [self.mapView addAnnotation:_carAnnotation];
-
实现mapView代理方法,根据userData来区分不同的Marker
- (QAnnotationView *)mapView:(QMapView *)mapView viewForAnnotation:(id<QAnnotation>)annotation { static NSString *reuse = @"annotation"; static NSString *reuseCar = @"annotationCar"; QPinAnnotationView *annotationView = (QPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuse]; if (annotationView == nil) { if (annotation == _carAnnotation) { annotationView = [[QPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseCar]; annotationView.image = [UIImage imageNamed:@"car"]; // 将小车的AnnotationView保存为属性,用于操作转向 _carAnnotationView = annotationView; } else { annotationView = [[QPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuse]; } } return annotationView; }
-
根据三角函数,计算起点和终点的角度,并调整小车Marker的角度
- (void)annotationRotate { // 取出终点坐标位置 CLLocationCoordinate2D toCoord = _bjAnnotation.coordinate; double fromLat = _carAnnotation.coordinate.latitude; double fromlon = _carAnnotation.coordinate.longitude; double toLat = toCoord.latitude; double tolon = toCoord.longitude; double slope = ((toLat - fromLat) / (tolon - fromlon)); double radio = atan(slope); double angle = 180 * (radio / M_PI); if (slope > 0) { if (tolon < fromlon) { angle = -90 - angle; } else { angle = 90 - angle; } } else if (slope == 0) { if (tolon < fromlon) { angle = -90; } else { angle = 90; } } else { if (toLat < fromLat) { angle = 90 - angle; } else { angle = -90 - angle; } } // 这里要注意,计算出来的是角度,而旋转则需要先转换为弧度 _carAnnotationView.transform = CGAffineTransformMakeRotation((M_PI * (angle) / 180.0)); }
在这个基础上,我在navigationItem中添加了一个切换当前途径点的功能,每次点击按钮就会将小车移动到下一个途经点,示例代码如下:
- (void)handleTestAction {
_index++;
if (_index == self.mapView.annotations.count - 2) {
_index = 0;
}
QPointAnnotation *annotation = self.mapView.annotations[_index];
_carAnnotation.coordinate = annotation.coordinate;
[self annotationRotate];
}
效果示例如下图所示:
如果帮助到了大家,请为我点个赞~~