高德地图提供包括:web前端、Android、iOS、服务器、小程序等平台的地图服务, 地图功能众多,本文记载的只是自己遇到的一些问题,绝大部分功能只要参照官方文档和Dome都可以实现出来。
下载SDK
注意:AMapFoundation.framework中提示含有 IDFA,我在一个设置了NSAppTransportSecurity为ture 的工程中使用,审核并没有被拒绝。
AppDelegate 中
#import <CoreLocation/CoreLocation.h> #import <AMapFoundationKit/AMapFoundationKit.h> <CLLocationManagerDelegate> { CLLocationManager *location; // 如果不设为全局的,弹框会一闪而过。 } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[AMapServices sharedServices] setEnableHTTPS:YES]; [AMapServices sharedServices].apiKey = @"6fc7498adXXXXXXXXXXX"; location = [[CLLocationManager alloc] init]; location.delegate= self; [location requestWhenInUseAuthorization];//弹框授权提示 }
需要展示地图的页面
#import <MAMapKit/MAMapView.h> <MAMapViewDelegate> myMapView = [[MAMapView alloc]init]; myMapView.bounds = CGRectMake(0, 0, WIDTH, HEIGHT); myMapView.center = CGPointMake(self.view.center.x, self.view.center.y); [myMapView setDelegate:self]; myMapView.showsCompass = NO; myMapView.showTraffic = NO; myMapView.showsScale = NO; myMapView.showsUserLocation = YES; //显示用户位置 myMapView.customizeUserLocationAccuracyCircleRepresentation = YES; [self.view addSubview:myMapView]; myMapView.rotateEnabled= NO; myMapView.rotateCameraEnabled = NO; [myMapView setCameraDegree:10.f animated:YES duration:0];//倾斜 myMapView.userTrackingMode = MAUserTrackingModeFollow; [myMapView setZoomLevel:18 animated:YES]; //定位显示在地图中心, 是代理方法, - (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation { //onceUserCenter为了避免因为一直定位造成的无法移动地图, if (!onceUserCenter) { coordinate = userLocation.coordinate; [myMapView setCenterCoordinate:coordinate]; } onceUserCenter = YES; }
如何自定义当前用户的定位图标:
//设置显示当前用户位置 myMapView.showsUserLocation = YES; //显示用户位置 //在某个经纬度下放置图标 MAPointAnnotation *annotation = [[MAPointAnnotation alloc]init]; annotation.coordinate = locationCorrrdinate; [_myMapView addAnnotations:@[annotation]]; // MyAnnation是一个自己定义的类 MyAnnation *annotation = [[MyAnnation alloc]initWithCoordinate:locationCorrrdinateGR]; [_myMapView addAnnotations:@[annotation]]; //这是一个专门显示地图上图标的方法体 是代理方法 - (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation { if ([annotation isKindOfClass:[MAPointAnnotation class]]) { static NSString *reuseIndetifier = @"annotationReuseIndetifier"; MAAnnotationView *annotationView = (MAAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseIndetifier]; if (annotationView == nil) { annotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIndetifier]; } annotationView.image = [UIImage imageNamed:@"annotation.png"]; //设置中心点偏移,使得标注底部中间点成为经纬度对应点 annotationView.centerOffset = CGPointMake(0, -18); return annotationView; } //找到当前定位点,如果这里不设置,那个默认的蓝点是不会消失的。 else if (annotation == mapView.userLocation) { static NSString *MAPCellIdentifier = @"MAPCellIdentifier"; MAAnnotationView *poiAnnotationView = (MAPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:MAPCellIdentifier]; if (poiAnnotationView == nil) { poiAnnotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:MAPCellIdentifier]; } poiAnnotationView.canShowCallout = NO; poiAnnotationView.image = [UIImage imageNamed:@"gc.png"]; return poiAnnotationView; } else if ([annotation isKindOfClass:[MyAnnation class]]){ } return nil; }`
效果如下:
F9F0B6AA-3483-4ABF-8823-A7C7AC8ED9E5.png
这里说明一下:MyAnnation是一个自己定义的类,如果需要你可以自定义很多这样的类,在代理中加以区分显示不同的图标,不过你也可以使用MAPointAnnotation 来加载,通过设置不同的标题title;来加以区分,这样是最简单的。
自定义MyAnnation 源码:
.h文件
#import <Foundation/Foundation.h> #import <MAMapKit/MAShape.h> @interface MyAnnation : NSObject <MAAnnotation> - (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate; @property (nonatomic, readwrite) CLLocationCoordinate2D coordinate; @property (nonatomic, copy) NSString *title; @property (nonatomic, copy) NSString *subtitle; @end
.m文件
#import "MyAnnation.h" @implementation MyAnnation - (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate { if(self = [super init]) self.coordinate = coordinate; return self; } @end
路线规划(在地图上显示两个地点之间的路线时)需要参照 iOS导航SDK,而不是 iOS地图SDK,不然你就走远啦
Snip20161118_1.png
参照高德开发文档中的步骤即可 路线参照文档,同时可以考高德地图的Dome中的示例代码。
源码:
#import <AMapNaviKit/AMapNaviKit.h> <MAMapViewDelegate,AMapNaviWalkManagerDelegate> { AMapNaviPoint *startPoint; AMapNaviPoint *endPoint; } @property (nonatomic,strong) AMapNaviWalkManager *walkManager; self.walkManager = [[MethodTool shareTool]backWalkManager]; [self.walkManager setDelegate:self]; startPoint = [AMapNaviPoint locationWithLatitude:locationCorrrdinate.latitude longitude:locationCorrrdinate.longitude]; endPoint = [AMapNaviPoint locationWithLatitude:locationCorrrdinateGR.latitude longitude:locationCorrrdinateGR.longitude]; [self routePlanAction]; #pragma mark-------------------地图路线规划 代理方法---------------- - (void)routePlanAction { //进行步行路径规划 [self.walkManager calculateWalkRouteWithStartPoints:@[startPoint] endPoints:@[endPoint]]; } // 路线规划成功时 - (void)walkManagerOnCalculateRouteSuccess:(AMapNaviWalkManager *)walkManager { NSLog(@"onCalculateRouteSuccess"); //显示路径或开启导航 if (walkManager.naviRoute == nil) { return; } [_myMapView removeOverlays:_myMapView.overlays]; NSUInteger coordianteCount = [walkManager.naviRoute.routeCoordinates count]; //使用一个定长的数组把返回的路线中的每个点都装起来,在加载到地图上即可 CLLocationCoordinate2D coordinates[coordianteCount]; for (int i = 0; i < coordianteCount; i++) { AMapNaviPoint *aCoordinate = [walkManager.naviRoute.routeCoordinates objectAtIndex:i]; coordinates[i] = CLLocationCoordinate2DMake(aCoordinate.latitude, aCoordinate.longitude); } MAPolyline *polyline = [MAPolyline polylineWithCoordinates:coordinates count:coordianteCount]; [_myMapView addOverlay:polyline]; [_myMapView setVisibleMapRect:[polyline boundingMapRect] animated:YES]; [_myMapView setHeight:Scale_Y(200)]; self.toUpdateA(); } //绘制路线的方法 - (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id<MAOverlay>)overlay { if ([overlay isKindOfClass:[MAPolyline class]]) //路线 { MAPolylineRenderer *polylineView = [[MAPolylineRenderer alloc] initWithOverlay:overlay]; //设置路线宽度 polylineView.lineWidth = Scale_X(6); //设置路线在地图上显示的颜色 polylineView.strokeColor = RGB(255, 170, 166, 1); return polylineView; } return nil; } - (void)walkManager:(AMapNaviWalkManager *)walkManager error:(NSError *)error; { NSLog(@"error: %@",error); } - (void)walkManager:(AMapNaviWalkManager *)walkManager onCalculateRouteFailure:(NSError *)error; { NSLog(@"error11: %@",error); }
效果大概如下:
注意导航规划路线的时候,AMapNaviWalkManager对象整个工程只能有一个,如果有多个,那么后面初始化的 AMapNaviWalkManager 是无法规划路线的。所以我使用了单例来保存这个对象供全局使用。
高德提供不依赖地图的定位,实现后台定位、持续定位:
在Info.plist中加入两个字段
NSLocationAlwaysUsageDescription NSLocationWhenInUseUsageDescription
这两个字段会义提示用户授权使用地理定位功能时的提示语。
<key>NSLocationAlwaysUsageDescription</key> <true/> <key>NSLocationWhenInUseUsageDescription</key> <true/>
如果实现后台持续定位,需要开启后台模式,并且这两个字段一个都不能少,否则不会出现如下效果。
定位使用时会出现手机顶部提示的
源码:
#import <AMapFoundationKit/AMapFoundationKit.h> #import <AMapLocationKit/AMapLocationKit.h> <AMapLocationManagerDelegate> @property(strong,nonatomic)AMapLocationManager *locationManager; self.locationManager = [[AMapLocationManager alloc] init]; self.locationManager.delegate = self; self.locationManager.distanceFilter = 100; if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) { self.locationManager.allowsBackgroundLocationUpdates = YES; }else{ [self.locationManager setPausesLocationUpdatesAutomatically:NO]; } //开启持续定位 - (void)startUploadLocation; { //开始持续定位 [self.locationManager startUpdatingLocation]; } - (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode { NSLog(@"location:{lat:%f; lon:%f; accuracy:%f}", location.coordinate.latitude, location.coordinate.longitude, location.horizontalAccuracy); [self uploadLoction:location.coordinate]; }
不过值得注意的是,在退出的时候不要忘记关掉持续定位,否则退出账号后还是会在后台显示定位。
- (void)endUpLoadLocation { //关闭持续定位 [self.locationManager stopUpdatingLocation]; }
逆地理编码(坐标转地址)为例源码:
#import <AMapSearchKit/AMapSearchKit.h> #import "ReGeocodeAnnotation.h" <AMapSearchDelegate> @property(strong,nonatomic)AMapSearchAPI *search; { AMapReGeocodeSearchRequest *regeo = [[AMapReGeocodeSearchRequest alloc] init]; regeo.location = [AMapGeoPoint locationWithLatitude:myMapView.centerCoordinate.latitude longitude:myMapView.centerCoordinate.longitude]; regeo.requireExtension = YES; [self.search AMapReGoecodeSearch:regeo]; } /* 逆地理编码回调. */ - (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response { if (response.regeocode != nil) { [MBProgressHUD hideHUDForView:self.view]; self.newAddressBlock(response.regeocode.formattedAddress); NSLog(@"addressComponent :%@",response.regeocode.addressComponent); [self.navigationController popViewControllerAnimated:YES]; } }
注意在地理编码与逆地理编码的解析中会使用到一些类文件,可以在高德的SDK中直接Copy过来使用。
关于根据地址解析出经纬度.使用系统自带的方法和使用高德的方法。
[[FBLocationManger shareManger]getUserGeography:@"XXXXXXXXX"]; [FBLocationManger shareManger].bolck = ^(CLLocationCoordinate2D loca) { NSLog(@"高德地址: %f %f",loca.longitude,loca.latitude); [myMapView setCenterCoordinate:loca]; [myMapView setHeight:Scale_Y(200)]; MyAnnation *annotation = [[MyAnnation alloc]initWithCoordinate:loca]; [myMapView addAnnotations:@[annotation]]; }; [[CCLocationManager shareLocation]getCodeFormAdress:@"杭州市滨江区建业路511号华业大厦" withCode:^(CLLocationCoordinate2D locationCorrrdinate) { NSLog(@"系统自带的地址: %f %f",locationCorrrdinate.longitude,locationCorrrdinate.latitude); [myMapView setCenterCoordinate:locationCorrrdinate]; [myMapView setHeight:Scale_Y(200)]; MAPointAnnotation *annotation = [[MAPointAnnotation alloc]init]; annotation.coordinate = locationCorrrdinate; [myMapView addAnnotations:@[annotation]]; }];
你会发现使用系统自带的你想地址解析API解析出来的经纬度更加准确,图中A是目的地,使用高德经纬度解析解析出来的是B。
综上所述,我们可以总结下:
关于地理编码与逆地理编码 根据地址反编译出经纬度,使用系统的方法比使用高德的方法更精确; 根据经纬度获得地址,使用高德的方法比使用系统的方法更精确;系统的方法定位出的地址有偏差。
认真跟着步骤配置工程,bundle文件没导入正确 使用iOS 地图 SDK设备加载地图显示白屏怎么办
增加GLKit.framework系统库就可以了
以上只是比较基础的地图应用,如果后续有用的新的功能,或者新的发现,会持续更新本文...... 如有错误,欢迎留言指正,谢谢。
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句