跟蹤顯示用戶的位置
設(shè)置MKMapView的userTrackingMode屬性可以跟蹤顯示用戶的當(dāng)前位置
MKUserTrackingModeNone
:不跟蹤用戶的位置
MKUserTrackingModeFollow
:跟蹤并在地圖上顯示用戶的當(dāng)前位置
MKUserTrackingModeFollowWithHeading
:跟蹤并在地圖上顯示用戶的當(dāng)前位置蔗彤,地圖會(huì)跟隨用戶的前進(jìn)方向進(jìn)行旋轉(zhuǎn)
下圖是跟蹤效果
藍(lán)色發(fā)光圓點(diǎn)就是用戶的當(dāng)前位置
藍(lán)色發(fā)光原點(diǎn)芙粱,專業(yè)術(shù)語(yǔ)叫做“大頭針”
地圖的類型
可以通過(guò)設(shè)置MKMapView的mapType 設(shè)置地圖類型
MKMapTypeStandard
:普通地圖(左圖)
MKMapTypeSatellite
:衛(wèi)星云圖 (中圖)
MKMapTypeHybrid
:混合模式(普通地圖覆蓋于衛(wèi)星云圖之上
)
MKMapTypeSatelliteFlyover: 3D立體衛(wèi)星 (iOS9.0)
MKMapTypeHybridFlyover: 3D立體混合 (iOS9.0)
設(shè)置地圖的其他屬性
操作項(xiàng):
是否可縮放 zoomEnabled
是否可滾動(dòng) scrollEnabled
是否可旋轉(zhuǎn) rotateEnabled
顯示項(xiàng):
是否顯示指南針 showsCompass (iOS9.0)
是否顯示比例尺 showsScale (iOS9.0)
是否顯示交通 showsTraffic (iOS9.0)
是否顯示建筑 showsBuildings
使用注意
設(shè)置對(duì)應(yīng)的屬性時(shí)钠乏,注意該屬性是從哪個(gè)系統(tǒng)版本開(kāi)始引入的,做好不同系統(tǒng)版本的適配
追蹤用戶的位置
設(shè)置MKMapView的userTrackingMode屬性可以跟蹤顯示用戶的當(dāng)前位置
MKUserTrackingModeNone
:不跟蹤用戶的位置
MKUserTrackingModeFollow
:跟蹤并在地圖上顯示用戶的當(dāng)前位置
MKUserTrackingModeFollowWithHeading
:跟蹤并在地圖上顯示用戶的當(dāng)前位置,地圖會(huì)跟隨用戶的前進(jìn)方向進(jìn)行旋轉(zhuǎn)
下圖是跟蹤效果
藍(lán)色發(fā)光圓點(diǎn)就是用戶的當(dāng)前位置
藍(lán)色發(fā)光圓點(diǎn),專業(yè)術(shù)語(yǔ)叫做“大頭針”
注意:iOS8.0之后究飞,追蹤用戶位置需要用戶進(jìn)行定位授權(quán)
備注:
iOS8.0-,地圖不會(huì)自動(dòng)滾動(dòng)到用戶所在位置
iOS8.0+堂鲤,地圖會(huì)自動(dòng)放大到合適比例亿傅,并顯示出用戶位置
MKMapView的代理
MKMapView可以設(shè)置一個(gè)代理對(duì)象,用來(lái)監(jiān)聽(tīng)地圖的相關(guān)行為
常見(jiàn)的代理方法有
- (void)mapView:(MKMapView*)mapView
didUpdateUserLocation:(MKUserLocation *)userLocation;
調(diào)用非常頻繁瘟栖,不斷監(jiān)測(cè)用戶的當(dāng)前位置
每次調(diào)用葵擎,都會(huì)把用戶的最新位置(userLocation參數(shù))傳進(jìn)來(lái)
- (void)mapView:(MKMapView*)mapView
regionWillChangeAnimated:(BOOL)animated;
地圖的顯示區(qū)域即將發(fā)生改變的時(shí)候調(diào)用
- (void)mapView:(MKMapView*)mapView
regionDidChangeAnimated:(BOOL)animated;
地圖的顯示區(qū)域已經(jīng)發(fā)生改變的時(shí)候調(diào)用
MKUserLocation
MKUserLocation其實(shí)是個(gè)大頭針模型,包括以下屬性
@property (nonatomic, copy) NSString*title;
顯示在大頭針上的標(biāo)題
@property (nonatomic, copy) NSString*subtitle;
顯示在大頭針上的子標(biāo)題
@property (readonly, nonatomic) CLLocation*location;
地理位置信息(大頭針釘在什么地方?)
設(shè)置地圖的顯示
通過(guò)MKMapView的下列方法慢宗,可以設(shè)置地圖顯示的位置和區(qū)域
設(shè)置地圖的中心點(diǎn)位置
@property (nonatomic) CLLocationCoordinate2DcenterCoordinate;
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
設(shè)置地圖的顯示區(qū)域
@property (nonatomic) MKCoordinateRegionregion;
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;
MKCoordinateRegion
MKCoordinateRegion是一個(gè)用來(lái)表示區(qū)域的結(jié)構(gòu)體坪蚁,定義如下
typedef struct{
CLLocationCoordinate2Dcenter; 區(qū)域的中心點(diǎn)位置
MKCoordinateSpanspan;
區(qū)域的跨度
} MKCoordinateRegion;
MKCoordinateSpan的定義
typedef struct{
CLLocationDegrees
latitudeDelta; 緯度跨度
CLLocationDegrees
longitudeDelta; 經(jīng)度跨度
}
MKCoordinateSpan;
MKUserLocation
MKUserLocation其實(shí)是個(gè)大頭針模型奔穿,包括以下屬性
@property (nonatomic, copy) NSString*title;
顯示在大頭針上的標(biāo)題
@property (nonatomic, copy) NSString*subtitle;
顯示在大頭針上的子標(biāo)題
@property (readonly, nonatomic) CLLocation*location;
地理位置信息(大頭針釘在什么地方?)
大頭針的基本操作
添加一個(gè)大頭針
- (void)addAnnotation:(id<MKAnnotation>)annotation;
添加多個(gè)大頭針
- (void)addAnnotations:(NSArray*)annotations;
移除一個(gè)大頭針
- (void)removeAnnotation:(id<MKAnnotation>)annotation;
移除多個(gè)大頭針
- (void)removeAnnotations:(NSArray*)annotations;
(id<MKAnnotation>)annotation參數(shù)是什么東西?
大頭針模型對(duì)象:用來(lái)封裝大頭針的數(shù)據(jù)敏晤,比如大頭針的位置贱田、標(biāo)題、子標(biāo)題等數(shù)據(jù)
大頭針模型
新建一個(gè)大頭針模型類
import <MapKit/MapKit.h>
@interface
MJTuangouAnnotation : NSObject <MKAnnotation>
/** 坐標(biāo)位置 */
@property(nonatomic, assign) CLLocationCoordinate2Dcoordinate;
/** 標(biāo)題 */
@property(nonatomic, copy) NSString*title;
/** 子標(biāo)題 */
@property(nonatomic, copy) NSString*subtitle;
@end
添加大頭針
MJTuangouAnnotation*anno = [[MJTuangouAnnotation
alloc] init];
anno.title = @"傳智播客iOS學(xué)院";
anno.subtitle = @"全部課程15折嘴脾,會(huì)員20折男摧,老學(xué)員30折";
anno.coordinate = CLLocationCoordinate2DMake(40, 116);
[self.mapView addAnnotation:anno];
自定義大頭針
如何自定義大頭針
設(shè)置MKMapView的代理
實(shí)現(xiàn)下面的代理方法,返回大頭針控件
- (MKAnnotationView
*)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation;
根據(jù)傳進(jìn)來(lái)的(id <MKAnnotation>)annotation參數(shù)創(chuàng)建并返回對(duì)應(yīng)的大頭針控件
代理方法的使用注意
如果返回nil译打,顯示出來(lái)的大頭針就采取系統(tǒng)的默認(rèn)樣式
標(biāo)識(shí)用戶位置的藍(lán)色發(fā)光圓點(diǎn)耗拓,它也是一個(gè)大頭針,當(dāng)顯示這個(gè)大頭針時(shí)奏司,也會(huì)調(diào)用代理方法
因此乔询,需要在代理方法中分清楚(id<MKAnnotation>)annotation參數(shù)代表自定義的大頭針還是藍(lán)色發(fā)光圓點(diǎn)
自定義大頭針
- (MKAnnotationView
*)mapView:(MKMapView *)mapView
viewForAnnotation:(id<MKAnnotation>)annotation
{
判斷annotation的類型
if
(![annotation isKindOfClass:[MJTuangouAnnotation class]])
return nil;
創(chuàng)建MKAnnotationView
static NSString *ID = @"tuangou";
MKAnnotationView
*annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID];
if (annoView
== nil) {
annoView = [[MKAnnotationView alloc]
initWithAnnotation:annotationreuseIdentifier:ID];
annoView.canShowCallout
= YES;
}
自定義大頭針
傳遞模型數(shù)據(jù)
annoView.annotation
= annotation;
設(shè)置圖片
MJTuangouAnnotation
*tuangouAnnotation = annotation;
annoView.image
= [UIImage imageNamed:tuangouAnnotation.icon];
return
annoView;
}
MKAnnotationView
地圖上的大頭針控件是MKAnnotationView
MKAnnotationView的屬性
@property (nonatomic, strong) id<MKAnnotation> annotation;
大頭針模型
@property (nonatomic, strong) UIImage*image;
顯示的圖片
@property (nonatomic) BOOLcanShowCallout;
是否顯示標(biāo)注
@property (nonatomic) CGPointcalloutOffset;
標(biāo)注的偏移量
@property (strong, nonatomic) UIView
*rightCalloutAccessoryView;
標(biāo)注右邊顯示什么控件
@property (strong, nonatomic) UIView
*leftCalloutAccessoryView;
標(biāo)注左邊顯示什么控件
MKPinAnnotationView
MKPinAnnotationView是MKAnnotationView的子類
MKPinAnnotationView比MKAnnotationView多了2個(gè)屬性
@property (nonatomic) MKPinAnnotationColorpinColor;
大頭針顏色
@property (nonatomic) BOOLanimatesDrop;
大頭針第一次顯示時(shí)是否從天而降
MKMapItem調(diào)用系統(tǒng)APP進(jìn)行導(dǎo)航
主要方法
[MKMapItem openMapsWithItems:items launchOptions:md];
示例代碼
根據(jù)兩個(gè)地標(biāo)對(duì)象進(jìn)行調(diào)用系統(tǒng)導(dǎo)航
- (void)beginNavWithBeginPlacemark:(CLPlacemark
*)beginPlacemark andEndPlacemark:(CLPlacemark *)endPlacemark
{
創(chuàng)建起點(diǎn):根據(jù)
CLPlacemark 地標(biāo)對(duì)象創(chuàng)建MKPlacemark 地標(biāo)對(duì)象
MKPlacemark *itemP1 = [[MKPlacemark alloc]
initWithPlacemark:beginPlacemark];
MKMapItem *item1 = [[MKMapItem alloc]
initWithPlacemark:itemP1];
創(chuàng)建終點(diǎn):根據(jù)
CLPlacemark 地標(biāo)對(duì)象創(chuàng)建MKPlacemark 地標(biāo)對(duì)象
MKPlacemark *itemP2 = [[MKPlacemark alloc]
initWithPlacemark:endPlacemark];
MKMapItem *item2 = [[MKMapItem alloc]
initWithPlacemark:itemP2];
NSDictionary *launchDic = @{
設(shè)置導(dǎo)航模式參數(shù)
MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,
設(shè)置地圖類型
MKLaunchOptionsMapTypeKey :
@(MKMapTypeHybridFlyover),
設(shè)置是否顯示交通
MKLaunchOptionsShowsTrafficKey : @(YES),
};
根據(jù)
MKMapItem 數(shù)組 和 啟動(dòng)參數(shù)字典
來(lái)調(diào)用系統(tǒng)地圖進(jìn)行導(dǎo)航
[MKMapItem openMapsWithItems:@[item1, item2]
launchOptions:launchDic];
}
MKMapCamera地圖街景
主要方法
self.mapView.camera = camera;
示例代碼
創(chuàng)建視角中心坐標(biāo)
CLLocationCoordinate2D
center = CLLocationCoordinate2DMake(23.132931, 113.375924);
創(chuàng)建3D視角
MKMapCamera *camera = [MKMapCamera
cameraLookingAtCenterCoordinate:center
fromEyeCoordinate:CLLocationCoordinate2DMake(center.latitude + 0.001,
center.longitude + 0.001) eyeAltitude:1];
設(shè)置到地圖上顯示
self.mapView.camera = camera;
MKMapSnapshotter地圖截圖
主要方法
[snapshotter startWithCompletionHandler:^(MKMapSnapshot
- _Nullable snapshot, NSError * _Nullable error) { }];
示例代碼
截圖附加選項(xiàng)
MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
設(shè)置截圖區(qū)域(在地圖上的區(qū)域,作用在地圖)
options.region = self.mapView.region;
options.mapRect = self.mapView.visibleMapRect;
設(shè)置截圖后的圖片大小(作用在輸出圖像)
options.size = self.mapView.frame.size;
設(shè)置截圖后的圖片比例(默認(rèn)是屏幕比例,
作用在輸出圖像)
options.scale = [[UIScreen mainScreen] scale];
MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc]
initWithOptions:options];
[snapshotter startWithCompletionHandler:^(MKMapSnapshot *_Nullable snapshot,
NSError
- _Nullable error) {
if
(error) {
NSLog(@"截圖錯(cuò)誤:%@",error.localizedDescription);
}else
{
設(shè)置屏幕上圖片顯示
self.snapshootImageView.image = snapshot.image;
將圖片保存到指定路徑(此處是桌面路徑韵洋,需要根據(jù)個(gè)人電腦不同進(jìn)行修改)
NSData *data = UIImagePNGRepresentation(snapshot.image);
[data writeToFile:@"/Users/wangshunzi/Desktop/snap.png"
atomically:YES];
}
}];
MKDirections獲取導(dǎo)航路線信息
主要方法
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse * _Nullable response,
NSError * _Nullable error) {
}];
繪制路線,添加覆蓋層等
主要方法
注意:這里不像添加大頭針那樣竿刁,只要我們添加了大頭針模型,默認(rèn)就會(huì)在地圖上添加系統(tǒng)的大頭針視圖
添加覆蓋層搪缨,需要我們實(shí)現(xiàn)對(duì)應(yīng)的代理方法食拜,在代理方法中返回對(duì)應(yīng)的覆蓋層
[self.mapView addOverlay:overlay];
調(diào)用了以上方法后,會(huì)調(diào)用以下代理方法獲取對(duì)應(yīng)的渲染涂層
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
MapKit框架的使用
一. 地圖的基本使用
- 設(shè)置地圖顯示類型
地圖的樣式可以手動(dòng)設(shè)置, 在iOS9.0之前有3種, iOS9.0之后增加了2種
1.設(shè)置方式
self.mapView.mapType = MKMapTypeStandard;
2.枚舉類型
對(duì)應(yīng)含義
MKMapTypeStandard
標(biāo)準(zhǔn)地圖
MKMapTypeSatellite
衛(wèi)星地圖
MKMapTypeHybrid
混合模式(標(biāo)準(zhǔn)+衛(wèi)星)
MKMapTypeSatelliteFlyover
3D立體衛(wèi)星(iOS9.0)
MKMapTypeHybridFlyover
3D立體混合(iOS9.0)
- 設(shè)置地圖控制項(xiàng)
地圖的旋轉(zhuǎn), 縮放, 移動(dòng)等等操作行為都可以開(kāi)啟或者關(guān)閉
設(shè)置方式
self.customMapView.zoomEnabled = YES; 是否縮放
self.customMapView.scrollEnabled = YES; 是否滾動(dòng)
self.customMapView.rotateEnabled = YES; 是否旋轉(zhuǎn)
self.customMapView.pitchEnabled = NO; 是否顯示3DVIEW
- 設(shè)置地圖顯示項(xiàng)
地圖上的指南針, 比例尺, 建筑物, POI點(diǎn)都可以控制是否顯示
設(shè)置方式
self.customMapView.showsCompass = YES; 是否顯示指南針
self.customMapView.showsScale = YES; 是否顯示比例尺
self.customMapView.showsTraffic = YES; 是否顯示交通
self.customMapView.showsBuildings = YES; 是否顯示建筑物
- 顯示用戶位置
可以設(shè)置顯示用戶當(dāng)前所在位置, 以一個(gè)藍(lán)點(diǎn)的形式呈現(xiàn)在地圖上
設(shè)置方式
方案1:(BOOL值)
self.customMapView.showsUserLocation =YES;
效果:
會(huì)在地圖上顯示一個(gè)藍(lán)點(diǎn), 標(biāo)識(shí)用戶所在位置; 但地圖不會(huì)縮放, 而且當(dāng)用戶位置移動(dòng)時(shí), 地圖不會(huì)跟隨用戶位置移動(dòng)而移動(dòng)
方案2:(追蹤方向模式)
self.customMapView.userTrackingMode =
MKUserTrackingModeFollowWithHeading;
效果:
會(huì)在地圖上顯示一個(gè)藍(lán)點(diǎn), 標(biāo)識(shí)用戶所在位置; 而且地圖縮放到合適比例,顯示用戶位置, 當(dāng)用戶位置移動(dòng)時(shí), 地圖會(huì)跟隨用戶位置移動(dòng)而移動(dòng); 但是有時(shí)候失效;
注意事項(xiàng): 如果要顯示用戶位置, 在iOS8.0之后, 需要主動(dòng)請(qǐng)求用戶授權(quán)
測(cè)試環(huán)境
加載地圖數(shù)據(jù)需要聯(lián)網(wǎng)
XCode版本根據(jù)測(cè)試選擇不同版本(iOS9.0 只能使用XCode7.0版本)
iOS系統(tǒng)版本根據(jù)測(cè)試選擇不同版本(例如地圖類型, 在iOS9.0之后才有新增)
常見(jiàn)問(wèn)題總結(jié)
地圖加載不顯示?
檢查網(wǎng)絡(luò)是否通暢
- 地圖放的太大都是格子, 禁止瀏覽
正常, 為了安全等原因, 不會(huì)看的太詳細(xì)
- 地圖運(yùn)行起來(lái)APP占用內(nèi)存非常大
正常, 地圖加載了很多資源
- 用戶位置不顯示
首先, 檢查代碼, 是否有設(shè)置顯示用戶位置,是否有進(jìn)行請(qǐng)求位置授權(quán)
其次, 查看模擬器是否有位置信息
第三, 重置模擬器, 模擬器又發(fā)神經(jīng)了.
二. 地圖的中級(jí)使用
- 查看當(dāng)前用戶位置信息
設(shè)置地圖代理
實(shí)現(xiàn)代理方法
-(void)mapView:(MKMapView *)mapView
didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(@"%@", userLocation);
}
- 調(diào)整地圖顯示中心
確定地圖中心經(jīng)緯度坐標(biāo)
CLLocationCoordinate2D
center = CLLocationCoordinate2DMake(21.123, 121.345);
設(shè)置地圖中心為給定的經(jīng)緯度坐標(biāo)
[mapView
setCenterCoordinate:center animated:YES];
- 調(diào)整地圖顯示區(qū)域
獲取合適的區(qū)域跨度
實(shí)現(xiàn)當(dāng)?shù)貓D區(qū)域發(fā)生改變時(shí)調(diào)用的代理代理方法, 并調(diào)整地圖區(qū)域到合適比例, 并在對(duì)應(yīng)的方法中, 獲取對(duì)應(yīng)的跨度信息
代碼如下:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
NSLog(@"%f---%f",
mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta);
}
創(chuàng)建一個(gè)區(qū)域(包含區(qū)域中心, 和區(qū)域跨度)
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(21.123, 121.345);
MKCoordinateSpan span = MKCoordinateSpanMake(0.1, 0.1);
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
設(shè)置地圖顯示區(qū)域
[self.mapView setRegion:region animated:YES];
概念解釋
MKCoordinateSpan
跨度解釋:
latitudeDelta:緯度跨度,因?yàn)槟媳本暩?0.0度副编,所以此值的范圍是(0.0---180.0)负甸;此值表示,整個(gè)地圖視圖寬度痹届,顯示多大跨度;
longitudeDelta:經(jīng)度跨度呻待,因?yàn)闁|西經(jīng)各180.0度,所以此值范圍是(0.0---360.0):此值表示短纵,整個(gè)地圖視圖高度带污,顯示多大跨度;
注意:地圖視圖顯示,不會(huì)更改地圖的比例香到,會(huì)以地圖視圖高度或?qū)挾容^小的那個(gè)為基準(zhǔn),按比例調(diào)整
- MKUserLocation 大頭針數(shù)據(jù)模型詳解
MKUserLocation
: 被稱作“大頭針(數(shù)據(jù))模型”;
其實(shí)喊什么都行报破,本質(zhì)就是一個(gè)數(shù)據(jù)模型悠就,只不過(guò)此模型遵循了大頭針要遵循的協(xié)議(MKAnnotation)
重要屬性:
location
: 用戶當(dāng)前所在位置信息(CLLocation對(duì)象)
title
: 大頭針標(biāo)注要顯示的標(biāo)題(NSString對(duì)象)
subtitle
: 大頭針標(biāo)注要顯示的子標(biāo)題(NSString對(duì)象)
測(cè)試環(huán)境
加載地圖數(shù)據(jù)需要聯(lián)網(wǎng)
XCode版本不限
iOS系統(tǒng)版本不限
常見(jiàn)問(wèn)題總結(jié)
地圖上的藍(lán)點(diǎn)為啥不顯示?
第一: 確定代碼是否有誤(例如, 是否顯示了用戶位置)
第二: 確定模擬器是否設(shè)置位置
第三: 看下位置在哪, 是不是不在當(dāng)前地圖顯示區(qū)域
- 地圖跨度設(shè)置之后,
最終顯示的跨度和設(shè)置數(shù)值不一致?
因?yàn)榈厍虻牟皇钦叫蔚? 隨著用戶的位置移動(dòng), 會(huì)自動(dòng)修正地圖跨度, 保持地圖不變形;
三. 地圖高級(jí)-大頭針基本使用
- 理論支撐(必須掌握)
按照MVC的原則
- 在地圖上操作大頭針,實(shí)際上是控制大頭針數(shù)據(jù)模型
添加大頭針就是添加大頭針數(shù)據(jù)模型
刪除大頭針就是刪除大頭針數(shù)據(jù)模型
- 在地圖上添加大頭針視圖
自定義大頭針數(shù)據(jù)模型
創(chuàng)建繼承自NSObject的數(shù)據(jù)模型XMGAnnotation,
遵循大頭針數(shù)據(jù)模型必須遵循的協(xié)議(MKAnnotation)注意將協(xié)議@property 中的readonly 去掉;
創(chuàng)建大頭針數(shù)據(jù)模型, 并初始化參數(shù)
XMGAnnotation *annotation = [[XMGAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = @"小碼哥";
annotation.subtitle = @"小碼哥分部";
調(diào)用地圖的添加大頭針數(shù)據(jù)模型方法
[self.customMapView addAnnotation:annotation];
- 移除大頭針(所有大頭針)
NSArray *annotations = self.customMapView.annotations;
[self.customMapView removeAnnotations:annotations];
- 場(chǎng)景模擬
場(chǎng)景描述:
鼠標(biāo)點(diǎn)擊在地圖哪個(gè)位置, 就在對(duì)應(yīng)的位置添加一個(gè)大頭針, 并在標(biāo)注彈框中顯示對(duì)應(yīng)的城市和街道;
實(shí)現(xiàn)步驟
- 獲取觸摸點(diǎn)在地圖上對(duì)應(yīng)的坐標(biāo)
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.customMapView];
- 將坐標(biāo)轉(zhuǎn)換成為經(jīng)緯度
CLLocationCoordinate2D center = [self.customMapView
convertPoint:touchPoint toCoordinateFromView:self.customMapView];
- 根據(jù)經(jīng)緯度創(chuàng)建大頭針數(shù)據(jù)模型, 并添加在地圖上
XMGAnnotation *annotation = [[XMGAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = @"小碼哥";
annotation.subtitle = @"小碼哥分部";
[self.customMapView addAnnotation:annotation];
- 利用反地理編碼,
獲取該點(diǎn)對(duì)應(yīng)的城市和街道名稱, 然后修改大頭針數(shù)據(jù)模型
注意: 設(shè)置彈框數(shù)據(jù)時(shí), 對(duì)應(yīng)的大頭針數(shù)據(jù)模型應(yīng)有對(duì)應(yīng)的占位數(shù)據(jù)(這樣對(duì)應(yīng)的UI才會(huì)生成,后面才能重新修改數(shù)據(jù))
測(cè)試環(huán)境
加載地圖數(shù)據(jù)需要聯(lián)網(wǎng)
XCode版本不限
iOS系統(tǒng)版本不限
常見(jiàn)問(wèn)題總結(jié)
反地理編碼無(wú)法獲取對(duì)應(yīng)的數(shù)據(jù)
第一: 檢查是否有聯(lián)網(wǎng)
第二: 檢查代碼是否有誤
第三: 有時(shí)存在某些位置沒(méi)有反地理編碼結(jié)果, 換個(gè)點(diǎn)嘗試, 如果都沒(méi)有, 排除此原因
- 大頭針協(xié)議遵循,屬性?
@property , 其實(shí)就是生成了get,
和 set 方法;
所以, 遵循這個(gè)協(xié)議, 等同于實(shí)現(xiàn)該屬性的get, set方法
四. 地圖高級(jí)-大頭針的自定義
- 理論支撐
按照MVC的原則
每當(dāng)添加一個(gè)大頭針數(shù)據(jù)模型時(shí), 地圖就會(huì)調(diào)用對(duì)應(yīng)的代理方法, 查找對(duì)應(yīng)的大頭針視圖,顯示在地圖上;
如果該方法沒(méi)有實(shí)現(xiàn), 或者返回nil, 那么就會(huì)使用系統(tǒng)默認(rèn)的大頭針視圖
- 模擬系統(tǒng)默認(rèn)的大頭針實(shí)現(xiàn)方案
實(shí)現(xiàn)當(dāng)添加大頭針數(shù)據(jù)模型時(shí),地圖回調(diào)的代理方法
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(XMGAnnotation *)annotation
{
}
實(shí)現(xiàn)須知
大頭針系統(tǒng)對(duì)應(yīng)的視圖是 MKPinAnnotationView,它繼承自MKAnnotationView
地圖上的大頭針視圖充易,和tableview上的cell一樣梗脾,都使用“循環(huán)利用”的機(jī)制
實(shí)現(xiàn)代碼
static NSString *pinID = @"pinID";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView
dequeueReusableAnnotationViewWithIdentifier:pinID];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:nil
reuseIdentifier:pinID];
}
pinView.annotation = annotation;
彈出標(biāo)注
pinView.canShowCallout = YES;
修改大頭針顏色
pinView.pinColor = MKPinAnnotationColorPurple;
設(shè)置大頭針從天而降
pinView.animatesDrop = YES;
設(shè)置大頭針可以被拖拽(父類中的屬性)
pinView.draggable =YES;
return pinView;
- 自定義大頭針
實(shí)現(xiàn)當(dāng)添加大頭針數(shù)據(jù)模型時(shí),地圖回調(diào)的代理方法
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(XMGAnnotation *)annotation
{
}
實(shí)現(xiàn)須知
如果想要自定義大頭針, 必須使用MKAnnotationView 或者 自定義的子類
但是不能直接使用系統(tǒng)默認(rèn)的大頭針, 會(huì)無(wú)效
實(shí)現(xiàn)代碼
自定義大頭針
static NSString *pinID = @"pinID";
MKAnnotationView *customPinView = [mapView dequeueReusableAnnotationViewWithIdentifier:pinID];
if (!customPinView) {
customPinView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:pinID];
}
設(shè)置大頭針圖片
customPinView.image = [UIImage imageNamed:@"category_3"];
設(shè)置大頭針可以彈出標(biāo)注
customPinView.canShowCallout = YES;
設(shè)置標(biāo)注左側(cè)視圖
UIImageView *leftIV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
leftIV.image = [UIImage imageNamed:@"huba.jpeg"];
customPinView.leftCalloutAccessoryView = leftIV;
設(shè)置標(biāo)注右側(cè)視圖
UIImageView *rightIV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
rightIV.image = [UIImage imageNamed:@"eason.jpg"];
customPinView.rightCalloutAccessoryView = rightIV;
設(shè)置標(biāo)注詳情視圖(iOS9.0)
customPinView.detailCalloutAccessoryView = [[UISwitch alloc] init];
return customPinView;
- 代理方法補(bǔ)充
選中一個(gè)大頭針時(shí)調(diào)用
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
NSLog(@"選中%@", [view.annotation title]);
}
取消選中大頭針時(shí)調(diào)用
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
NSLog(@"取消選中%@", [view.annotation title]);
}
測(cè)試環(huán)境
加載地圖數(shù)據(jù)需要聯(lián)網(wǎng)
XCode版本不限
iOS系統(tǒng)版本不限
常見(jiàn)問(wèn)題總結(jié)
代碼運(yùn)行在低版本的XCode上, 編譯失敗
第一: 語(yǔ)法錯(cuò)誤; XCode7.0 對(duì)于OC語(yǔ)法優(yōu)化了一些, 需要手動(dòng)調(diào)整
第二: iOS9.0的SDK, 在XCode7.0之前的版本沒(méi)有對(duì)應(yīng)的API
五. 利用系統(tǒng)App導(dǎo)航
導(dǎo)航的三種實(shí)現(xiàn)方案
可以將需要導(dǎo)航的位置丟給系統(tǒng)的地圖APP進(jìn)行導(dǎo)航
發(fā)送網(wǎng)絡(luò)請(qǐng)求到公司服務(wù)器獲取導(dǎo)航數(shù)據(jù), 然后自己手動(dòng)繪制導(dǎo)航
利用三方SDK實(shí)現(xiàn)導(dǎo)航(百度)
- 直接將起點(diǎn)和終點(diǎn), 傳遞給系統(tǒng)地圖, 利用系統(tǒng)APP, 進(jìn)行導(dǎo)航
利用"反推法", 記住關(guān)鍵代碼即可
代碼如下:
根據(jù)兩個(gè)地標(biāo)對(duì)象進(jìn)行調(diào)用系統(tǒng)導(dǎo)航
- (void)beginNavWithBeginPlacemark:(CLPlacemark *)beginPlacemark andEndPlacemark:(CLPlacemark *)endPlacemark
{
創(chuàng)建起點(diǎn):根據(jù)CLPlacemark 地標(biāo)對(duì)象創(chuàng)建MKPlacemark 地標(biāo)對(duì)象
MKPlacemark *itemP1 = [[MKPlacemark alloc] initWithPlacemark:beginPlacemark];
MKMapItem *item1 = [[MKMapItem alloc] initWithPlacemark:itemP1];
創(chuàng)建終點(diǎn):根據(jù)CLPlacemark 地標(biāo)對(duì)象創(chuàng)建MKPlacemark 地標(biāo)對(duì)象
MKPlacemark *itemP2 = [[MKPlacemark alloc] initWithPlacemark:endPlacemark];
MKMapItem *item2 = [[MKMapItem alloc] initWithPlacemark:itemP2];
NSDictionary *launchDic = @{
設(shè)置導(dǎo)航模式參數(shù)
MKLaunchOptionsDirectionsModeKey :
MKLaunchOptionsDirectionsModeDriving,
設(shè)置地圖類型
MKLaunchOptionsMapTypeKey : @(MKMapTypeHybridFlyover),
設(shè)置是否顯示交通
MKLaunchOptionsShowsTrafficKey : @(YES),
};
根據(jù) MKMapItem 數(shù)組 和 啟動(dòng)參數(shù)字典 來(lái)調(diào)用系統(tǒng)地圖進(jìn)行導(dǎo)航
[MKMapItem openMapsWithItems:@[item1, item2] launchOptions:launchDic];
}
注意: CLPlacemark地標(biāo)對(duì)象沒(méi)法直接手動(dòng)創(chuàng)建, 只能通過(guò)(反)地理編碼獲取
- 補(bǔ)充
3D視圖
補(bǔ)充1:類似于地圖街景,增強(qiáng)用戶體驗(yàn)
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(23.132931, 113.375924);
MKMapCamera *camera = [MKMapCamera cameraLookingAtCenterCoordinate:center fromEyeCoordinate:CLLocationCoordinate2DMake(center.latitude, center.longitude + 0.001) eyeAltitude:1];
self.mapView.camera = camera;
地圖截圖
截圖附加選項(xiàng)
MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
設(shè)置截圖區(qū)域(在地圖上的區(qū)域,作用在地圖)
options.region =self.mapView.region;
options.mapRect = self.mapView.visibleMapRect;
設(shè)置截圖后的圖片大小(作用在輸出圖像)
options.size =self.mapView.frame.size;
設(shè)置截圖后的圖片比例(默認(rèn)是屏幕比例盹靴,
作用在輸出圖像)
options.scale = [[UIScreen mainScreen] scale];
MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler:^(MKMapSnapshot * _Nullable
snapshot, NSError * _Nullable error) {
if (error) {
NSLog(@"截圖錯(cuò)誤:%@",error.localizedDescription);
}else
{
設(shè)置屏幕上圖片顯示
self.snapshootImageView.image =
snapshot.image;
將圖片保存到指定路徑(此處是桌面路徑炸茧,需要根據(jù)個(gè)人電腦不同進(jìn)行修改)
NSData *data = UIImagePNGRepresentation(snapshot.image);
[data writeToFile:@"/Users/wangshunzi/Desktop/snap.png"
atomically:YES];
}
}];
測(cè)試環(huán)境
加載地圖數(shù)據(jù)需要聯(lián)網(wǎng)
XCode版本不限
iOS系統(tǒng)版本不限
常見(jiàn)問(wèn)題總結(jié)
需要注意地標(biāo)對(duì)象不能手動(dòng)創(chuàng)建, 因?yàn)槔锩娴膶傩允莚eadonly; 只能通過(guò)(反)地理編碼獲取
六. 獲取導(dǎo)航路線信息
- 實(shí)現(xiàn)須知
獲取導(dǎo)航路線, 需要想蘋(píng)果服務(wù)器發(fā)送網(wǎng)絡(luò)請(qǐng)求
記住關(guān)鍵對(duì)象MKDirections
2.代碼實(shí)現(xiàn)
根據(jù)兩個(gè)地標(biāo)瑞妇,向蘋(píng)果服務(wù)器請(qǐng)求對(duì)應(yīng)的行走路線信息
- (void)directionsWithBeginPlackmark:(CLPlacemark
*)beginP andEndPlacemark:(CLPlacemark *)endP
{
創(chuàng)建請(qǐng)求
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
設(shè)置開(kāi)始地標(biāo)
MKPlacemark *beginMP = [[MKPlacemark alloc] initWithPlacemark:beginP];
request.source = [[MKMapItem alloc] initWithPlacemark:beginMP];
設(shè)置結(jié)束地標(biāo)
MKPlacemark *endMP = [[MKPlacemark alloc] initWithPlacemark:endP];
request.destination = [[MKMapItem alloc] initWithPlacemark:endMP];
根據(jù)請(qǐng)求,獲取實(shí)際路線信息
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions
calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *
_Nullable response,
NSError * _Nullableerror) {
[response.routes enumerateObjectsUsingBlock:^(MKRoute * _Nonnull obj, NSUInteger
idx,
BOOL * _Nonnull
stop) {
NSLog(@"%@--", obj.name);
[obj.steps enumerateObjectsUsingBlock:^(MKRouteStep * _Nonnull
obj, NSUInteger idx, BOOL *_Nonnull stop) {
NSLog(@"%@",
obj.instructions);
}];
}];
}];
}
- 導(dǎo)航路線對(duì)象詳解
/**
MKDirectionsResponse對(duì)象解析
source :開(kāi)始位置
destination :結(jié)束位置
routes : 路線信息 (MKRoute對(duì)象)
MKRoute對(duì)象解析
name : 路的名稱
advisoryNotices :
注意警告信息
distance :
路線長(zhǎng)度(實(shí)際物理距離梭冠,單位是m)
polyline :
路線對(duì)應(yīng)的在地圖上的幾何線路(由很多點(diǎn)組成辕狰,可繪制在地圖上)
steps :
多個(gè)行走步驟組成的數(shù)組(例如“前方路口左轉(zhuǎn)”,“保持直行”等等控漠,
MKRouteStep 對(duì)象)
MKRouteStep對(duì)象解析
instructions :
步驟說(shuō)明(例如“前方路口左轉(zhuǎn)”蔓倍,“保持直行”等等)
transportType :
通過(guò)方式(駕車,步行等)
polyline :
路線對(duì)應(yīng)的在地圖上的幾何線路(由很多點(diǎn)組成盐捷,可繪制在地圖上)
注意:
MKRoute是一整條長(zhǎng)路偶翅;MKRouteStep是這條長(zhǎng)路中的每一截;
*/
測(cè)試環(huán)境
請(qǐng)求路線數(shù)據(jù)需要聯(lián)網(wǎng)
XCode版本不限
iOS系統(tǒng)版本不限
常見(jiàn)問(wèn)題總結(jié)
類太多, 記不住咋辦?
此功能不常用, 只需要知道有這一個(gè)功能. 如果到時(shí)用到, 直接回過(guò)頭來(lái)找代碼;
七. 繪制導(dǎo)航路線
- 理論支持
1.路線也是一個(gè)覆蓋層
在地圖上操作覆蓋層,其實(shí)操作的是覆蓋層的數(shù)據(jù)模型
添加覆蓋層:在地圖上添加覆蓋層數(shù)據(jù)模型 刪除覆蓋層:在地圖上移除覆蓋層數(shù)據(jù)模型
- 添加導(dǎo)航路線到地圖
1.獲取幾何路線的數(shù)據(jù)模型(id
)overlay
2.地圖添加覆蓋層(幾何路線也是一個(gè)覆蓋層), 直接添加覆蓋層數(shù)據(jù)模型
[self.mapView addOverlay:overlay];
3.設(shè)置地圖代理, 代理遵循協(xié)議
MKMapViewDelegate
4.實(shí)現(xiàn)地圖添加覆蓋層數(shù)據(jù)模型時(shí), 回調(diào)的代理方法; 通過(guò)此方法, 返回對(duì)應(yīng)的渲染圖層
- (MKOverlayRenderer
*)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
創(chuàng)建折線渲染對(duì)象
if ([overlay isKindOfClass:[MKPolyline class]])
{
MKPolylineRenderer *lineRenderer = [[MKPolylineRenderer alloc]
initWithOverlay:overlay];
設(shè)置線寬
lineRenderer.lineWidth = 6;
設(shè)置線顏色
lineRenderer.strokeColor = [UIColor redColor];
return lineRenderer;
}
}
- 練習(xí): 添加圓形覆蓋層到地圖
1.創(chuàng)建圓形區(qū)域覆蓋層的數(shù)據(jù)模型
MKCircle *circle =
[MKCircle circleWithCenterCoordinate:self.mapView.centerCoordinate
radius:1000000];
2.添加覆蓋層數(shù)據(jù)模型
[self.mapView addOverlay:circle];
3.實(shí)現(xiàn)代理方法
-(MKOverlayRenderer
*)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
創(chuàng)建圓形區(qū)域渲染對(duì)象
if ([overlay isKindOfClass:[MKCircle class]])
{
MKCircleRenderer *circleRender = [[MKCircleRenderer alloc]
initWithOverlay:overlay];
circleRender.fillColor = [UIColor cyanColor];
circleRender.alpha = 0.6;
return circleRender;
}
return nil;
}
測(cè)試環(huán)境
地圖加載需要聯(lián)網(wǎng)
XCode版本不限
iOS系統(tǒng)版本不限
常見(jiàn)問(wèn)題總結(jié)
東西太多, 記不住?
只需要記得一個(gè)思想, 按照MVC的原則, 我們操作覆蓋層, 就是操作覆蓋層數(shù)據(jù)模型; 然后地圖, 會(huì)調(diào)用其對(duì)應(yīng)的代理方法, 獲取對(duì)應(yīng)的覆蓋層渲染層;
類記不住沒(méi)關(guān)系, 主要記住大致思路就可以.
八. 集成百度地圖
集成原因
有些功能, 系統(tǒng)自帶的高德地圖無(wú)法實(shí)現(xiàn), 例如POI檢索等等
一般實(shí)現(xiàn)導(dǎo)航功能,
會(huì)集成百度地圖的比較多;
集成步驟
下載對(duì)應(yīng)的SDK
按照集成文檔一步一步實(shí)現(xiàn)
開(kāi)發(fā)經(jīng)驗(yàn)
不要把所有的功能全部都寫(xiě)在控制器當(dāng)中, 最好封裝成一個(gè)單獨(dú)的工具類
如果集成過(guò)程中出現(xiàn)問(wèn)題, 先查看官方文檔
測(cè)試環(huán)境
需要聯(lián)網(wǎng)
XCode版本不限
iOS系統(tǒng)版本不限
- 常見(jiàn)問(wèn)題總結(jié)
按照開(kāi)發(fā)文檔一步一步做, 一般沒(méi)有什么問(wèn)題; 注意集成細(xì)節(jié)就行.