App需求如下:
1,App连接蓝牙设备,此时App端开始记录GPS位置信息;
2,App蓝牙连接断开,此时App端统计GPS位置轨迹,并绘制在地图上显示
使用2种地图原因:高德地图国外显示不了、Google地图国内显示不了
注:还有一个原因是因为通过手机系统SDK获取得到的GPS位置有偏移
系统SDK得到的位置为国际标准WGS-84
国内的位置标准为GCJ-02(火星坐标)
由于业务需求,我在App启动的时候,就做了判断当前位置是否在国内,然后统计数据保存一个(国内、外)状态至数据库。
逻辑如下:
1,App启动,使用CLLocationManager获取到location
2,使用CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
BOOL isChina = NO;
if (placemarks.count > 0) {
CLPlacemark * placemark = placemarks[0];
//通过该判断是为CN,还有HK,TW等,自行判断吧
isChina = [placemark.ISOcountryCode isEqualToString:@"CN"];
}
}];
3,当isChina为YES时,使用高德地图来获取位置更新
当isChina为NO时,使用系统SDK来获取位置更新
(代码就不贴粗来了,应该难不到谁吧?)
4,这个时候就是贴代码的时候了【Google地图轨迹绘制】
//默认显示【北京】也可以不设置默认
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:39.7072013727
longitude:116.5429835110
zoom:12];
_mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
//创建轨迹路径集合
GMSMutablePath *path = [GMSMutablePath path];
for(MALocationModel *m in locations){
[path addLatitude:m.latitude longitude:m.longitude];
}
//轨迹线图对象
_polyline = [GMSPolyline polylineWithPath:path];
_polyline.strokeWidth = 5;
_polyline.map = _mapView;
//设置地图轨迹屏幕可视区域
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithPath:path];
GMSCameraPosition *position = [_mapView cameraForBounds:bounds insets:UIEdgeInsetsZero];
_mapView.camera = position;
到了这里,地图轨迹基本就出来了(上面insets:UIEdgeInsetsZero可以自行设置)。
4.1添加起点图标【自定义View】
CLLocationCoordinate2D position_start = CLLocationCoordinate2DMake(latitude,longitude);
GMSMarker *start = [GMSMarker markerWithPosition:position_start];
start.title = nil;
start.icon = [UIImage imageNamed:@"record_map_start_icon"];
start.map = _mapView;
注意问题:有可能轨迹地图显示的zoomlevel需要手动调整下
[_mapView animateToZoom:[self levelWithMileage:10]];【如下】
5,高德地图轨迹绘制【上代码】
self.mapView = [[MAMapView alloc] initWithFrame:self.bounds];
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.mapView.delegate = self;
self.mapView.showsCompass = NO;
self.mapView.showsScale = NO;
self.mapView.zoomLevel = 17;
//显示轨迹
-(void)showDefaultMap
{
NSMutableArray *arr = [NSMutableArray array];
for(MALocationModel *m in self.recordInfo.locations){
MATracePoint *point = [[MATracePoint alloc] init];
point.latitude = m.latitude;
point.longitude = m.longitude;
[arr addObject:point];
}
CLLocationCoordinate2D start = CLLocationCoordinate2DMake(((MATracePoint *)[arr firstObject]).latitude, ((MATracePoint *)[arr firstObject]).longitude);
CLLocationCoordinate2D end = CLLocationCoordinate2DMake(((MATracePoint *)[arr lastObject]).latitude, ((MATracePoint *)[arr lastObject]).longitude);
[self addAnnotationWithCooordinate:start title:@"start"];
[self addAnnotationWithCooordinate:end title:@"end"];
self.processedOverlays = [NSMutableArray array];
[self addFullTrace:arr toMapView:self.mapView];
}
//添加图标
-(void)addAnnotationWithCooordinate:(CLLocationCoordinate2D)coordinate title:(NSString *)title
{
MAPointAnnotation *annotation = [[MAPointAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = title;
annotation.subtitle = @"CustomAnnotationView2";
[self.mapView addAnnotation:annotation];
}
- (void)addFullTrace:(NSArray<MATracePoint*> *)tracePoints toMapView:(MAMapView *)mapView
{
[self.mapView hiddenHUD];
//此类用于定义一个由多个点相连的多段线
MAMultiPolyline *polyline = [self makePolyLineWith:tracePoints];
if(!polyline) {
return;
}
[self.processedOverlays addObject:polyline];
[mapView addOverlays:self.processedOverlays];
UIEdgeInsets edge = UIEdgeInsetsMake(20, 20, 20, 20);
if (_showSetting) {
edge = UIEdgeInsetsMake(50, 30, 50, 30);
}
[mapView setVisibleMapRect:polyline.boundingMapRect edgePadding:edge animated:NO];
[mapView setZoomLevel:[self levelWithMileage:self.recordInfo.distance/1000.f] animated:NO];
}
//划线
- (MAMultiPolyline *)makePolyLineWith:(NSArray<MATracePoint*> *)tracePoints {
if(tracePoints.count == 0) {
return nil;
}
CLLocationCoordinate2D *pCoords = malloc(sizeof(CLLocationCoordinate2D) * tracePoints.count);
if(!pCoords) {
return nil;
}
for(int i = 0; i < tracePoints.count; ++i) {
MATracePoint *p = [tracePoints objectAtIndex:i];
CLLocationCoordinate2D *pCur = pCoords + i;
pCur->latitude = p.latitude;
pCur->longitude = p.longitude;
}
//分段绘制,根据经纬度坐标数据生成多段线
MAMultiPolyline *polyline = [MAMultiPolyline polylineWithCoordinates:pCoords count:tracePoints.count drawStyleIndexes:@[@10, @60]];
if(pCoords) {
free(pCoords);
}
return polyline;
}
//绘制覆盖物
#pragma mark - MAMapViewDelegate
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id <MAOverlay>)overlay
{
if ([overlay isKindOfClass:[MAMultiPolyline class]])
{
MAPolylineRenderer *polylineView = [[MAPolylineRenderer alloc] initWithPolyline:(MAPolyline *)overlay];
polylineView.lineWidth = 6.f;
polylineView.strokeColor = RGB(0, 182, 249);
//路线填充图片
polylineView.strokeImage = [UIImage imageNamed:@"icon_map_arrow"];
polylineView.lineJoinType = kCGLineJoinRound;//连接类型
polylineView.lineCapType = kCGLineCapRound;//端点类型
return polylineView;
}
return nil;
}
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation
{
if ([annotation isKindOfClass:[MAPointAnnotation class]]) {
static NSString *ident = @"pointIdent";
MAAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:ident];
if (annotationView == nil)
{
annotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ident];
// must set to NO, so we can show the custom callout view.
annotationView.canShowCallout = NO;
annotationView.draggable = YES;
}
if ([annotation.title isEqualToString:@"start"]) {
annotationView.image = [UIImage imageNamed:@"record_map_start_icon"];
}else if ([annotation.title isEqualToString:@"end"]){
annotationView.image = [UIImage imageNamed:@"record_map_end_icon"];
}
return annotationView;
}
return nil;
}
-(int)levelWithMileage:(CGFloat)mileage
{
int level = 15;
if (mileage > 1000) {
level = 3;
}else if (mileage > 500){
level = 4;
}else if (mileage > 200){
level = 5;
}else if (mileage > 100){
level = 6;
}else if (mileage > 50){
level = 7;
}else if (mileage > 30){
level = 8;
}else if (mileage > 20){
level = 9;
}else if (mileage > 10){
level = 10;
}else if (mileage > 5){
level = 11;
}else if (mileage > 1){
level = 13;
}else{
level = 14;
}
return level;
}