前言
高德地圖提供包括:web前端屯烦、Android、iOS首启、服務(wù)器暮屡、小程序等平臺(tái)的地圖服務(wù), 地圖功能眾多毅桃,本文記載的只是自己遇到的一些問題褒纲,絕大部分功能只要參照官方文檔和Dome都可以實(shí)現(xiàn)出來(lái)准夷。
本文目錄
- 地圖的基本顯示
- 地圖上放置圖標(biāo)
- 在地圖上繪制路線路線
- 后臺(tái)持續(xù)定位
- 地理編碼與逆地理編碼
- 遇到的問題
地圖的基本顯示
注意:AMapFoundation.framework中提示含有 IDFA,我在一個(gè)設(shè)置了NSAppTransportSecurity為ture 的工程中使用莺掠,審核并沒有被拒絕衫嵌。
AppDelegate 中
#import <CoreLocation/CoreLocation.h>
#import <AMapFoundationKit/AMapFoundationKit.h>
<CLLocationManagerDelegate>
{
CLLocationManager *location; // 如果不設(shè)為全局的,彈框會(huì)一閃而過彻秆。
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[AMapServices sharedServices] setEnableHTTPS:YES];
[AMapServices sharedServices].apiKey = @"6fc7498adXXXXXXXXXXX";
location = [[CLLocationManager alloc] init];
location.delegate= self;
[location requestWhenInUseAuthorization];//彈框授權(quán)提示
}
需要展示地圖的頁(yè)面
#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為了避免因?yàn)橐恢倍ㄎ辉斐傻臒o(wú)法移動(dòng)地圖,
if (!onceUserCenter) {
coordinate = userLocation.coordinate;
[myMapView setCenterCoordinate:coordinate];
}
onceUserCenter = YES;
}
地圖上放置圖標(biāo)
如何自定義當(dāng)前用戶的定位圖標(biāo):
//設(shè)置顯示當(dāng)前用戶位置
myMapView.showsUserLocation = YES; //顯示用戶位置
//在某個(gè)經(jīng)緯度下放置圖標(biāo)
MAPointAnnotation *annotation = [[MAPointAnnotation alloc]init];
annotation.coordinate = locationCorrrdinate;
[_myMapView addAnnotations:@[annotation]];
// MyAnnation是一個(gè)自己定義的類
MyAnnation *annotation = [[MyAnnation alloc]initWithCoordinate:locationCorrrdinateGR];
[_myMapView addAnnotations:@[annotation]];
//這是一個(gè)專門顯示地圖上圖標(biāo)的方法體 是代理方法
- (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"];
//設(shè)置中心點(diǎn)偏移唇兑,使得標(biāo)注底部中間點(diǎn)成為經(jīng)緯度對(duì)應(yīng)點(diǎn)
annotationView.centerOffset = CGPointMake(0, -18);
return annotationView;
}
//找到當(dāng)前定位點(diǎn)酒朵,如果這里不設(shè)置,那個(gè)默認(rèn)的藍(lán)點(diǎn)是不會(huì)消失的扎附。
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;
}`
效果如下:
這里說(shuō)明一下:MyAnnation是一個(gè)自己定義的類蔫耽,如果需要你可以自定義很多這樣的類,在代理中加以區(qū)分顯示不同的圖標(biāo)留夜,不過你也可以使用MAPointAnnotation 來(lái)加載针肥,通過設(shè)置不同的標(biāo)題title;來(lái)加以區(qū)分,這樣是最簡(jiǎn)單的香伴。
自定義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
在地圖上繪制路線
路線規(guī)劃(在地圖上顯示兩個(gè)地點(diǎn)之間的路線時(shí))需要參照 iOS導(dǎo)航SDK,而不是 iOS地圖SDK具则,不然你就走遠(yuǎn)啦
參照高德開發(fā)文檔中的步驟即可
路線參照文檔即纲,同時(shí)可以考高德地圖的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-------------------地圖路線規(guī)劃 代理方法----------------
- (void)routePlanAction
{
//進(jìn)行步行路徑規(guī)劃
[self.walkManager calculateWalkRouteWithStartPoints:@[startPoint]
endPoints:@[endPoint]];
}
// 路線規(guī)劃成功時(shí)
- (void)walkManagerOnCalculateRouteSuccess:(AMapNaviWalkManager *)walkManager
{
NSLog(@"onCalculateRouteSuccess");
//顯示路徑或開啟導(dǎo)航
if (walkManager.naviRoute == nil)
{
return;
}
[_myMapView removeOverlays:_myMapView.overlays];
NSUInteger coordianteCount = [walkManager.naviRoute.routeCoordinates count];
//使用一個(gè)定長(zhǎng)的數(shù)組把返回的路線中的每個(gè)點(diǎn)都裝起來(lái)博肋,在加載到地圖上即可
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];
//設(shè)置路線寬度
polylineView.lineWidth = Scale_X(6);
//設(shè)置路線在地圖上顯示的顏色
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);
}
效果大概如下:
注意導(dǎo)航規(guī)劃路線的時(shí)候低斋,AMapNaviWalkManager對(duì)象整個(gè)工程只能有一個(gè),如果有多個(gè)匪凡,那么后面初始化的 AMapNaviWalkManager 是無(wú)法規(guī)劃路線的膊畴。所以我使用了單例來(lái)保存這個(gè)對(duì)象供全局使用。
后臺(tái)持續(xù)定位
高德提供不依賴地圖的定位病游,實(shí)現(xiàn)后臺(tái)定位唇跨、持續(xù)定位:
高德地圖定位
在Info.plist中加入兩個(gè)字段
NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
這兩個(gè)字段會(huì)義提示用戶授權(quán)使用地理定位功能時(shí)的提示語(yǔ)。
<key>NSLocationAlwaysUsageDescription</key>
<true/>
<key>NSLocationWhenInUseUsageDescription</key>
<true/>
如果實(shí)現(xiàn)后臺(tái)持續(xù)定位衬衬,需要開啟后臺(tái)模式买猖,并且這兩個(gè)字段一個(gè)都不能少,否則不會(huì)出現(xiàn)如下效果滋尉。
源碼:
#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];
}
//開啟持續(xù)定位
- (void)startUploadLocation;
{
//開始持續(xù)定位
[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];
}
不過值得注意的是玉控,在退出的時(shí)候不要忘記關(guān)掉持續(xù)定位,否則退出賬號(hào)后還是會(huì)在后臺(tái)顯示定位狮惜。
- (void)endUpLoadLocation
{
//關(guān)閉持續(xù)定位
[self.locationManager stopUpdatingLocation];
}
地理編碼與逆地理編碼
逆地理編碼(坐標(biāo)轉(zhuǎn)地址)為例源碼:
#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];
}
/* 逆地理編碼回調(diào). */
- (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];
}
}
注意在地理編碼與逆地理編碼的解析中會(huì)使用到一些類文件高诺,可以在高德的SDK中直接Copy過來(lái)使用碌识。
關(guān)于根據(jù)地址解析出經(jīng)緯度.使用系統(tǒng)自帶的方法和使用高德的方法。
[[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:@"杭州市濱江區(qū)建業(yè)路511號(hào)華業(yè)大廈" withCode:^(CLLocationCoordinate2D locationCorrrdinate) {
NSLog(@"系統(tǒng)自帶的地址: %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]];
}];
你會(huì)發(fā)現(xiàn)使用系統(tǒng)自帶的你想地址解析API解析出來(lái)的經(jīng)緯度更加準(zhǔn)確虱而,圖中A是目的地筏餐,使用高德經(jīng)緯度解析解析出來(lái)的是B。
綜上所述,我們可以總結(jié)下:
關(guān)于地理編碼與逆地理編碼
根據(jù)地址反編譯出經(jīng)緯度薛窥,使用系統(tǒng)的方法比使用高德的方法更精確胖烛;
根據(jù)經(jīng)緯度獲得地址,使用高德的方法比使用系統(tǒng)的方法更精確诅迷;系統(tǒng)的方法定位出的地址有偏差佩番。
遇到的問題
-
iOS 自帶的地理位置反編譯,是需要聯(lián)萬(wàn)維網(wǎng)的罢杉,內(nèi)網(wǎng)開發(fā)中是不回有數(shù)據(jù)返回的趟畏。
iOS 自帶的地理位置反編譯返回的是拼音?那是因?yàn)槟愕氖謾C(jī)語(yǔ)言設(shè)置不是漢語(yǔ)環(huán)境滩租,而是英語(yǔ)環(huán)境赋秀。
-
路線規(guī)劃一直失敗
那是因?yàn)槟愕?Bundle ID在高德地圖中心沒有注冊(cè)。錯(cuò)誤碼:Error Domain=AMapNaviErrorDomain Code=2 "CalculateRouteError: 2(10008)" UserInfo={NSLocalizedDescription=CalculateRouteError: 2(10008)}
[AMapFoundationKit][Info] : Key驗(yàn)證失敗 - INVALID_USER_SCODE[28680c9926f2c44f88fdbc20476884e7]
-
若項(xiàng)目中使用地圖相關(guān)類律想,一定要檢測(cè)內(nèi)存情況猎莲,因?yàn)榈貓D是比較耗費(fèi)App內(nèi)存的,因此在根據(jù)文檔實(shí)現(xiàn)某地圖相關(guān)功能的同時(shí)技即,我們需要注意內(nèi)存的正確釋放著洼,大體需要注意的有需在使用完畢時(shí)將地圖、代理等滯空為nil而叼,注意地圖中標(biāo)注(大頭針)的復(fù)用身笤,并且在使用完畢時(shí)清空標(biāo)注數(shù)組等。
- (void)clearMapView{ self.mapView = nil; self.mapView.delegate =nil; self.mapView.showsUserLocation = NO; [self.mapView removeAnnotations:self.annotations]; [self.mapView removeOverlays:self.overlays]; [self.mapView setCompassImage:nil]; }
-
出現(xiàn)格格狀
(1)沒有網(wǎng)絡(luò)來(lái)驗(yàn)證用戶key葵陵,(2)APPKey 不對(duì)應(yīng) 液荸,(3)bundle文件沒導(dǎo)入正確認(rèn)真跟著步驟配置工程,bundle文件沒導(dǎo)入正確
使用iOS 地圖 SDK設(shè)備加載地圖顯示白屏怎么辦
-
iOS 大頭針怎么固定在地圖中間,且移動(dòng)地圖 怎么獲取到 大頭針下的具體位置經(jīng)緯度
把大頭針放在 視圖中心
myMapView.centerCoordinate 是高德地圖 API中定義的獲取地圖的方法脱篙。__weak typeof(self)weakSelf = self; [MBProgressHUD showHUDAddedTo:self.view animated:YES]; [[CCLocationManager shareLocation] getAdressFormCode:myMapView.centerCoordinate.latitude :myMapView.centerCoordinate.longitude withAddress:^(NSString *addressString) { [MBProgressHUD hideHUDForView:weakSelf.view]; weakSelf.newAddressBlock(addressString); [weakSelf.navigationController popViewControllerAnimated:YES]; }];
-
如何定位到當(dāng)前位置
//定位顯示在地圖中心 - (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation { if (!onceUserCenter) { coordinate = userLocation.coordinate; [myMapView setCenterCoordinate:coordinate]; } onceUserCenter = YES; }
-
在其它地方想回到開始的定位位置使用下面的方法:
[myMapView setCenterCoordinate:coordinate animated:YES];
提交AppStore必讀
引入了 IDFA娇钱,可能會(huì)造成您的應(yīng)用提交 AppStore 審核失敗,請(qǐng)您認(rèn)真閱讀下文绊困。-
編譯報(bào)錯(cuò)
增加GLKit.framework系統(tǒng)庫(kù)就可以了
-
寬度設(shè)置WIDTH 地圖是兩個(gè)屏幕的寬度忍弛。
//正常顯示 newMapView = [[MAMapView alloc] initWithFrame:CGRectMake(0, Scale_Y(50), view1.frame.size.width, Scale_Y(200))]; //地圖是兩個(gè)屏幕的寬度 newMapView = [[MAMapView alloc] initWithFrame:CGRectMake(0, Scale_Y(50), WIDTH, Scale_Y(200))];
-
關(guān)于地圖顯示太大,世界級(jí)地圖考抄?
//定位顯示在地圖中心 - (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation { if (!onceUserCenter) { coordinate = userLocation.coordinate; [myMapView setCenterCoordinate:coordinate]; [myMapView setHeight:Scale_Y(200)]; } onceUserCenter = YES; }
這樣就可以顯示當(dāng)前位置细疚,并展示小區(qū)域地圖了
-
如果你真的遇到問題,解決不了,加QQ群聊吧
-
如果你不知道到哪里找對(duì)應(yīng)的開發(fā)文檔疯兼,請(qǐng)搜索然遏,搜索可以解決絕大部分問題。
-
如何實(shí)現(xiàn)用戶方向的展示?
//根據(jù)頭部信息顯示方向 -(void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation{ if(nil == userLocation || nil == userLocation.heading || userLocation.heading.headingAccuracy < 0) { return; } //獲取頭部方向 CLLocationDirection theHeading = userLocation.heading.magneticHeading; float direction = theHeading; if(nil != _myLocationAnnotationView) { if (direction > 180) { direction = 360 - direction; } else { direction = 0 - direction; } _myLocationAnnotationView.image = [self.myLocationImage imageRotatedByDegrees:-direction]; } }
-
如何實(shí)現(xiàn)GPS信號(hào)的強(qiáng)弱的展示?
GPS信號(hào)是沒有直接數(shù)據(jù)的展示的.我們需要從回調(diào)方法的location參數(shù)中拿到horizontalAccuracy屬性和verticalAccuracy屬性的值,這兩個(gè)值就是判斷精度圈大小的,如果GPS信號(hào)弱的話,那么精度圈就會(huì)很大,horizontalAccuracy屬性和verticalAccuracy這兩個(gè)值就會(huì)很大.相反,如果GPS信號(hào)強(qiáng)的話,那么兩者的值就會(huì)很小.
typedef enum : NSUInteger { strengthGradeBest = 1,//信號(hào)最好 可精確到0-20米 strengthGradeBetter,//信號(hào)強(qiáng) 可精確到20-100米 strengthGradeAverage,//信號(hào)弱 可精確到100-200米 strengthGradeBad,//信號(hào)很弱 ,200米開外 } strengthGrade; - (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode{ locationModel.gpsStrength = [self gpsStrengthWithLocation:location]; } #pragma mark ---GPS信號(hào)強(qiáng)弱--- -(strengthGrade)gpsStrengthWithLocation:(CLLocation *)location{ if (location.horizontalAccuracy>200 &&location.verticalAccuracy >200) { return strengthGradeBad; } if (location.horizontalAccuracy>100 &&location.verticalAccuracy >100&&location.horizontalAccuracy<200 &&location.verticalAccuracy <200) { return strengthGradeAverage; } if (location.horizontalAccuracy>20 &&location.verticalAccuracy >20&&location.horizontalAccuracy<100 &&location.verticalAccuracy <100) { return strengthGradeBetter; } if (location.horizontalAccuracy<20 &&location.verticalAccuracy <20) { return strengthGradeBest; } return strengthGradeBad; }
小結(jié)
以上只是比較基礎(chǔ)的地圖應(yīng)用吧彪,如果后續(xù)有用的新的功能待侵,或者新的發(fā)現(xiàn),會(huì)持續(xù)更新本文......
如有錯(cuò)誤姨裸,歡迎留言指正秧倾,謝謝。