/**
MKMapTypeStandard = 0, // 標准
MKMapTypeSatellite, // 衛星
MKMapTypeHybrid, // 混合(標准+衛星)
MKMapTypeSatelliteFlyover NS_ENUM_AVAILABLE(10_11, 9_0), // 3D立體衛星
MKMapTypeHybridFlyover NS_ENUM_AVAILABLE(10_11, 9_0), // 3D立體混合
*/
self.customMapView.mapType = MKMapTypeStandard;
注意:設置對應屬性時,注意該屬性是從哪個系統版本開始引入的,做好不同系統版本的適配
// 是否可以縮放
self.customMapView.zoomEnabled = NO;
// 是否可以滾動
self.customMapView.scrollEnabled = NO;
// 是否可以旋轉
self.customMapView.rotateEnabled = NO;
// 是否顯示3D
self.customMapView.pitchEnabled = NO;
// 是否顯示指南針
self.customMapView.showsCompass = YES;
// 是否顯示比例尺
self.customMapView.showsScale = YES;
// 是否顯示交通
self.customMapView.showsTraffic = YES;
// 是否顯示建築物
self.customMapView.showsBuildings = YES;
-(CLLocationManager *)locationM
{
if (!_locationM) {
_locationM = [[CLLocationManager alloc] init];
if ([_locationM respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[_locationM requestAlwaysAuthorization];
}
}
return _locationM;
}
/**
MKUserTrackingModeNone = 0, // 不跟隨
MKUserTrackingModeFollow, // 跟隨用戶位置
MKUserTrackingModeFollowWithHeading, // 跟隨用戶位置,並跟隨用戶方向
*/
[self locationM];
self.customMapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
設置地圖代理,並實現代理方法,在代理方法中獲取用戶當前位置(注意iOS8.0之後要請求授權)
將地圖顯示中心調整為用戶當前所在位置(iOS之前,地圖不會自動移動到用戶所在位置)
調整當前地圖顯示的區域(可使用對應代理方法查看當前地圖跨度然後調整到合適的跨度即可)
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
/**
MKUserLocation : 被稱作“大頭針模型”,其實喊什麼都行,本質就是一個數據模型,只不過此模型遵循了大頭針要遵循的協議(MKAnnotation)
location: 用戶當前所在位置信息(CLLocation對象)
title: 大頭針標注要顯示的標題(NSString對象)
subtitle: 大頭針標注要顯示的子標題(NSString對象)
*/
// 根據用戶當前位置的經緯度,設置地圖顯示中心
/**
存在弊端:地圖顯示比例過大,無法調整
解決方案:直接使用對應的調整地圖“顯示區域”的API
*/
// [mapView setCenterCoordinate:userLocation.coordinate animated:YES];
/**
MKCoordinateSpan 跨度解釋:
latitudeDelta:緯度跨度,因為南北緯各90度,所以此值的范圍是(0---180);此值表示,整個地圖視圖寬度,顯示多大跨度
longitudeDelta:經度跨度,因為東西經各180度,所以此值范圍是(0---360):此值表示,整個地圖視圖高度,顯示多大跨度
注意:地圖視圖顯示,不會更改地圖的比例,會以地圖視圖高度或寬度較小的那個為基准,按比例調整
*/
// MKCoordinateSpan span = MKCoordinateSpanMake(0.1, 0.1);
// MKCoordinateRegion region = MKCoordinateRegionMake(userLocation.coordinate, span);
// [mapView setRegion:region animated:YES];
}
// 當地圖區域(跨度)改變時調用
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
NSLog(@"%f---%f", mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta);
}
在地圖上操作大頭針,實際上就是操作大頭針數據模型
添加大頭針就是添加大頭針數據模型
刪除大頭針就是刪除大頭針模型
實現步驟
添加一個/多個大頭針
自定義大頭針模型(需要遵循MKAnnotation協議)
#import
@interface XMGAnnotation : NSObject
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy, nullable) NSString *title;
@property (nonatomic, copy, nullable) NSString *subtitle;
@end
創建自定義大頭針模型,並添加到地圖上
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 如果我們僅僅添加大頭針數據模型,地圖上會自動添加系統默認的大頭針視圖
CYXAnnotation *annotation = [[CYXAnnotation alloc] init];
// annotation.coordinate = self.mapView.centerCoordinate;
// 1. 獲取當前點的位置
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self.mapView];
// 把點轉換成對應的經緯度
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
// TODO:使用反地理編碼,獲取對應大頭針的所在的位置信息,通過標注顯示出來
annotation.coordinate = coordinate;
annotation.title = @"荔灣區";
annotation.subtitle = @"和業廣場";
// 添加單個大頭針
[self.mapView addAnnotation:annotation];
// 添加多個大頭針
// [self.mapView addAnnotations:@[]];
}
移除1個/多個大頭針
[self.mapView removeAnnotations:self.mapView.annotations];
添加大頭針數據時,其實地圖會調用代理方法查找對應的大頭針視圖,如果沒有找到,就會使用系統默認的大頭針視圖
模擬系統大頭針實現方案,並對大頭針進行部分自定義
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
// 如果此方法返回nil, 就會使用系統自帶的大頭針視圖
// 模擬下,返回nil,系統的解決方案
static NSString *pinId = @"pinID";
MKPinAnnotationView *pinView = ( MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pinId];
if (pinView == nil) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinId];
}
pinView.annotation = annotation;
// 是否顯示標注
pinView.canShowCallout = YES;
// 設置大頭針顏色
pinView.pinColor = MKPinAnnotationColorPurple;
// 設置大頭針是否有下落動畫
pinView.animatesDrop = YES;
return pinView;
}
自定義大頭針
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
/** 自定義大頭針-------*/
static NSString *pinId = @"pinID";
MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:pinId];
if (annoView == nil) {
annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinId];
}
annoView.annotation = annotation;
annoView.image = [UIImage imageNamed:@"category_5"];
annoView.canShowCallout = YES;
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"huba.jpeg"]];
imageView.bounds = CGRectMake(0, 0, 44, 44);
annoView.leftCalloutAccessoryView = imageView;
imageView.userInteractionEnabled = YES;
UIImageView *imageView2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"eason.jpg"]];
imageView2.bounds = CGRectMake(0, 0, 44, 44);
annoView.rightCalloutAccessoryView = imageView2;
annoView.detailCalloutAccessoryView = [UISwitch new];
annoView.draggable = YES;
return annoView;
}
大頭針圖標,大頭針標注,左側視圖,右側視圖,詳情視圖,等;
選中和取消選中大頭針時的代理方法
// 點擊標注
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(@"點擊標注");
}
// 選中大頭針
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
NSLog(@"選中大頭針");
}
// 取消選中大頭針
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
NSLog(@"取消選中大頭針");
}
// 根據兩個地標對象進行調用系統導航
- (void)beginNavWithBeginPlacemark:(CLPlacemark *)beginPlacemark andEndPlacemark:(CLPlacemark *)endPlacemark
{
// 根據 CLPlacemark 地標對象創建 MKPlacemark 地標對象
MKPlacemark *itemP1 = [[MKPlacemark alloc] initWithPlacemark:beginPlacemark];
MKMapItem *item1 = [[MKMapItem alloc] initWithPlacemark:itemP1];
MKPlacemark *itemP2 = [[MKPlacemark alloc] initWithPlacemark:endPlacemark];
MKMapItem *item2 = [[MKMapItem alloc] initWithPlacemark:itemP2];
NSDictionary *launchDic = @{
// 設置導航模式參數
MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,
// 設置地圖類型
MKLaunchOptionsMapTypeKey : @(MKMapTypeHybridFlyover),
// 設置是否顯示交通
MKLaunchOptionsShowsTrafficKey : @(YES),
};
// 根據 MKMapItem 數組 和 啟動參數字典 來調用系統地圖進行導航
[MKMapItem openMapsWithItems:@[item1, item2] launchOptions:launchDic];
}
/**
補充1:類似於地圖街景,增強用戶體驗
*/
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(23.132931, 113.375924);
MKMapCamera *camera = [MKMapCamera cameraLookingAtCenterCoordinate:center fromEyeCoordinate:CLLocationCoordinate2DMake(center.latitude + 0.001, center.longitude + 0.001) eyeAltitude:1];
self.mapView.camera = camera;
/**
補充2:地圖截圖
*/
// 截圖附加選項
MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
// 設置截圖區域(在地圖上的區域,作用在地圖)
options.region = self.mapView.region;
// options.mapRect = self.mapView.visibleMapRect;
// 設置截圖後的圖片大小(作用在輸出圖像)
options.size = self.mapView.frame.size;
// 設置截圖後的圖片比例(默認是屏幕比例, 作用在輸出圖像)
options.scale = [[UIScreen mainScreen] scale];
MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler:^(MKMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
if (error) {
NSLog(@"截圖錯誤:%@",error.localizedDescription);
}else
{
// 設置屏幕上圖片顯示
self.snapshootImageView.image = snapshot.image;
// 將圖片保存到指定路徑(此處是桌面路徑,需要根據個人電腦不同進行修改)
NSData *data = UIImagePNGRepresentation(snapshot.image);
[data writeToFile:@"/Users/chenyanxiang/Desktop/snap.png" atomically:YES];
}
}];
// 根據兩個地標,向蘋果服務器請求對應的行走路線信息
- (void)directionsWithBeginPlackmark:(CLPlacemark *)beginP andEndPlacemark:(CLPlacemark *)endP
{
// 創建請求
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
// 設置開始地標
MKPlacemark *beginMP = [[MKPlacemark alloc] initWithPlacemark:beginP];
request.source = [[MKMapItem alloc] initWithPlacemark:beginMP];
// 設置結束地標
MKPlacemark *endMP = [[MKPlacemark alloc] initWithPlacemark:endP];
request.destination = [[MKMapItem alloc] initWithPlacemark:endMP];
// 根據請求,獲取實際路線信息
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) {
/**
MKDirectionsResponse對象解析
source :開始位置
destination :結束位置
routes : 路線信息 (MKRoute對象)
MKRoute對象解析
name : 路的名稱
advisoryNotices : 注意警告信息
distance : 路線長度(實際物理距離,單位是m)
polyline : 路線對應的在地圖上的幾何線路(由很多點組成,可繪制在地圖上)
steps : 多個行走步驟組成的數組(例如“前方路口左轉”,“保持直行”等等, MKRouteStep 對象)
MKRouteStep對象解析
instructions : 步驟說明(例如“前方路口左轉”,“保持直行”等等)
transportType : 通過方式(駕車,步行等)
polyline : 路線對應的在地圖上的幾何線路(由很多點組成,可繪制在地圖上)
注意:
MKRoute是一整條長路;MKRouteStep是這條長路中的每一截;
*/
[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);
}];
}];
}];
}
路線也是一個覆蓋層
理論指導:在地圖上操作覆蓋層,其實就是操作覆蓋層的數據模型
添加覆蓋層:在地圖上添加覆蓋層數據模型
刪除覆蓋層:在地圖上移除覆蓋層數據模型
1.創建路線覆蓋層模型,並添加到地圖上
// 繪制線路
- (void)drawMapLine:(id )overlay
{
/**
注意:這裡不像添加大頭針那樣,只要我們添加了大頭針模型,默認就會在地圖上添加系統的大頭針視圖
添加覆蓋層,需要我們實現對應的代理方法,在代理方法中返回對應的覆蓋層
*/
[self.mapView addOverlay:overlay];
/** 補充測試:添加一個圓形覆蓋層 */
// MKCircle *circle = [MKCircle circleWithCenterCoordinate:self.mapView.centerCoordinate radius:1000000];
// [self.mapView addOverlay:circle];
}
2.利用地圖的代理方法,返回對應的圖層渲染
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay{
// 創建折線渲染對象
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolylineRenderer *lineRenderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
// 設置線寬
lineRenderer.lineWidth = 6;
// 設置線顏色
lineRenderer.strokeColor = [UIColor redColor];
return lineRenderer;
}
// 創建圓形區域渲染對象
// if ([overlay isKindOfClass:[MKCircle class]]) {
// MKCircleRenderer *circleRender = [[MKCircleRenderer alloc] initWithOverlay:overlay];
// circleRender.fillColor = [UIColor cyanColor];
// circleRender.alpha = 0.6;
// return circleRender;
// }
return nil;
}