iOS學習筆記20 地圖(二)MapKit框架

###1、地圖開發介紹 從iOS6.0開始地圖數據再也不由谷歌驅動,而是改用自家地圖,固然在國內它的數據是由高德地圖提供的。 ######在iOS中進行地圖開發主要有三種方式:git

  • 利用MapKit框架進行地圖開發,利用這種方式能夠對地圖進行精準的控制
  • 調用蘋果官方自帶的地圖應用,主要用於一些簡單的地圖應用,沒法精確控制
  • 使用第三方地圖開發SDK庫

用得最多的仍是MapKit,因此這節就只講MapKit的使用。 ###2、MapKit核心類 MapKit的核心類爲地圖展現控件MKMapView,如下是經常使用的屬性、對象方法以及代理方法。 ####1. 屬性:數組

/* 用戶位置跟蹤 */
@property (nonatomic) BOOL showsUserLocation;/*< 是否在地圖上標註用戶位置 */
@property (nonatomic, readonly) MKUserLocation *userLocation;/*< 用戶位置 */
@property (nonatomic) MKUserTrackingMode userTrackingMode;/*< 用戶跟蹤類型 */
typedef NS_ENUM(NSInteger, MKUserTrackingMode) {
	MKUserTrackingModeNone = 0, /*< 不跟蹤 */
	MKUserTrackingModeFollow, /*< 跟蹤 */
	MKUserTrackingModeFollowWithHeading,  /*< 導航跟蹤 */
};
/* 設置地圖配置項 */
@property (nonatomic) MKMapType mapType;/*< 地圖類型 */
@property (nonatomic, readonly) NSArray *annotations;/*< 大頭針數組 */
typedef NS_ENUM(NSUInteger, MKMapType) {
    MKMapTypeStandard = 0,/*< 標準地圖 */
    MKMapTypeSatellite,/*< 衛星地圖 */
    MKMapTypeHybrid,/*< 混合模式(標準+衛星) */
    MKMapTypeSatelliteFlyover,/*< 3D立體衛星(iOS9.0) */
    MKMapTypeHybridFlyover,/*< 3D立體混合(iOS9.0) */
}
/* 設置地圖控制項 */
@property (nonatomic) BOOL zoomEnabled;/*< 是否能夠縮放 */
@property (nonatomic) BOOL scrollEnabled;/*< 是否能夠滾動 */
@property (nonatomic) BOOL rotateEnabled;/*< 是否能夠旋轉 */
@property (nonatomic) BOOL pitchEnabled;/*< 是否顯示3D視角 */
/* 設置地圖顯示項 */
@property (nonatomic) BOOL showsBuildings;/*< 是否顯示建築物,隻影響標準地圖 */
@property (nonatomic) BOOL showsTraffic;/*< 是否顯示交通,iOS9 */
@property (nonatomic) BOOL showsCompass;/*< 是否顯示指南針,iOS9 */
@property (nonatomic) BOOL showsScale;/*< 是否顯示比例尺,iOS9 */
複製代碼

所謂大頭針就是地圖上顯示的這個標註: 緩存

大頭針圖片
####2. 對象方法:

/* 添加大頭針 */
- (void)addAnnotation:(id <MKAnnotation>)annotation;
- (void)addAnnotations:(NSArray<id<MKAnnotation>> *)annotations;
/* 刪除大頭針 */
- (void)removeAnnotation:(id <MKAnnotation>)annotation;
- (void)removeAnnotations:(NSArray<id<MKAnnotation>> *)annotations;
/* 選中大頭針與取消選中大頭針 */
- (void)selectAnnotation:(id <MKAnnotation>)annotation 
                animated:(BOOL)animated;
- (void)deselectAnnotation:(id <MKAnnotation>)annotation 
                  animated:(BOOL)animated;
/* 獲取大頭針視圖 */
- (MKAnnotationView *)viewForAnnotation:(id <MKAnnotation>)annotation;
/* 從緩衝池中取出大頭針視圖控件 */
- (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier;
/* 設置顯示區域以及地圖中心座標 */
- (void)setRegion:(MKCoordinateRegion)region 
         animated:(BOOL)animated;
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate 
                   animated:(BOOL)animated;
/* 經緯度座標轉UIKit座標,UIKit座標轉經緯度座標 */
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate 
               toPointToView:(UIView *)view;
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point 
                  toCoordinateFromView:(UIView *)view;
複製代碼

####3. 經常使用代理方法MKMapViewDelegate框架

/* 地圖加載完成會調用 */
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView;
/* 地圖加載失敗會調用 */
- (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error;
/* 用戶位置發生改變會調用 */
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
/* 顯示區域改變會調用 */
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
/* 點擊選中大頭針時會調用 */
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view;
/* 取消選中大頭針時會調用 */
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view;
/* 顯示地圖上的大頭針,功能相似於UITableView的tableView:cellForRowAtIndexPath:方法 */
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation;
複製代碼

###3、MapKit使用 ####1. 首先添加頭文件:ide

#import <MapKit/MapKit.h>
複製代碼

####2. 初始化地圖展現控件MKMapView學習

- (void)initMapView{
    CGFloat x = 0;
    CGFloat y = 20;
    CGFloat width = self.view.frame.size.width;
    CGFloat height = self.view.frame.size.height;
    //建立MKMapView,設置控件視圖大小
    MKMapView *mapView = [[MKMapView alloc] initWithFrame:CGRectMake(x, y, width, height)];
    //設置地圖類型
    mapView.mapType = MKMapTypeStandard;
    //設置代理
    mapView.delegate = self;
    [self.view addSubview:mapView];
    self.mapView = mapView;
}
複製代碼

####3. 用戶位置跟蹤 ######在iOS8以前,實現這個功能只須要:優化

  1. 設置用戶跟蹤模式
  1. mapView:DidUpdateUserLocation:代理方法中設置地圖中心和顯示範圍

######在iOS8以後,用法稍有不一樣:ui

  1. 必須按照前面的定位章節的,獲取前臺或者先後臺的定位服務受權,下面是連接: iOS學習筆記19-地圖(一)定位CoreLocation
  1. 不須要進行中心點的指定,默認會將當前位置設置爲中心點並自動顯示區域範圍
  2. 只有定位到當前位置後mapView:DidUpdateUserLocation:代理方法纔會調用
- (void)viewDidLoad {
    [super viewDidLoad];
    //獲取定位服務受權
    [self requestUserLocationAuthor];
    //初始化MKMapView
    [self initMapView];
}
- (void)requestUserLocationAuthor{
    //若是沒有得到定位受權,獲取定位受權請求
    self.locationM = [[CLLocationManager alloc] init];
    if ([CLLocationManager locationServicesEnabled]) {
        if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
            [self.locationM requestWhenInUseAuthorization];
        }
    }
}
- (void)initMapView{
    CGFloat x = 0;
    CGFloat y = 20;
    CGFloat width = self.view.frame.size.width;
    CGFloat height = self.view.frame.size.height;
    //建立MKMapView對象
    MKMapView *mapView = [[MKMapView alloc] initWithFrame:CGRectMake(x, y, width, height)];
    //設置地圖類型
    mapView.mapType = MKMapTypeStandard;
    //設置用戶跟蹤模式
    mapView.userTrackingMode = MKUserTrackingModeFollow;
    mapView.delegate = self;
    [self.view addSubview:mapView];
    self.mapView = mapView;
}
#pragma mark - MKMapViewDelegate
/* 更新用戶位置會調用 */
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
    CLLocation *location = userLocation.location;
    CLLocationCoordinate2D coordinate = location.coordinate;
    NSLog(@"經度:%f,緯度:%f",coordinate.latitude,coordinate.longitude);
}
複製代碼

用戶位置跟蹤

####4. 添加大頭針 MapKit沒有自帶的大頭針,只有大頭針協議MKAnnotation,咱們須要自定義大頭針:atom

  1. 建立一個繼承NSObject的類
  1. 實現MKAnnotation協議
  2. 必須建立一個屬性,用於存儲大頭針位置
@property (nonatomic) CLLocationCoordinate2D coordinate;
複製代碼

######下面就是我簡單建立的LTAnnotation類:spa

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface LTAnnotation : NSObject <MKAnnotation>
/* 必須建立的屬性 */
@property (nonatomic) CLLocationCoordinate2D coordinate;
/* 可選的屬性 */
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
/* 自定義的屬性 */
@property (nonatomic, strong) UIImage *icon;
@end

@implementation LTAnnotation
@end
複製代碼

######下面是實際的使用:

- (void)viewDidLoad {
    [super viewDidLoad];
    //請求定位受權
    [self requestUserLocationAuthor];
    //初始化MKMapView
    [self initMapView];
    //添加大頭針
    [self addAnnotationsToMapView];
}
- (void)addAnnotationsToMapView{
    CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(22.54, 114.02);
    //建立大頭針
    LTAnnotation *annotation = [[LTAnnotation alloc] init];
    annotation.title = @"執着";
    annotation.subtitle = @"執着哥開的店";
    annotation.coordinate = location1;
    annotation.icon = [UIImage imageNamed:@"red"];
    //添加大頭針
    [self.mapView addAnnotation:annotation1];
}
複製代碼

大頭針在地圖上的顯示

點擊大頭針顯示

####5. 自定義大頭針視圖 上面的大頭針樣子是否是很醜,那是MKMapView的默認樣式大頭針視圖MKAnnotationView,咱們先來了解下它的經常使用屬性:

@property (nonatomic, strong) id<MKAnnotation> annotation;/*< 大頭針數據 */
@property (nonatomic, strong) UIImage *image;/*< 大頭針的圖標 */
@property (nonatomic, readonly) NSString *reuseIdentifier;/*< 大頭針的惟一標示 */
@property (nonatomic) CGPoint calloutOffset;/*< 彈出視圖的偏移 */
@property (nonatomic) BOOL selected;/*< 是否選中 */
@property (nonatomic) BOOL canShowCallout;/*< 是否能點擊彈出視圖 */
@property (nonatomic, strong) UIView *leftCalloutAccessoryView;/*< 彈出視圖左邊的視圖 */
@property (nonatomic, strong) UIView *rightCalloutAccessoryView;/*< 彈出視圖右邊的視圖 */
複製代碼

######下面是經過設置MKAnnotationView的屬性,自定義大頭針視圖:

/* 每當大頭針顯示在可視界面上時,就會調用該方法,用戶位置的藍色點也是個大頭針,也會調用 */
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    if ([annotation isKindOfClass:[LTAnnotation class]]) {
        LTAnnotation *annotationLT = (LTAnnotation *)annotation;
        //相似於UITableViewCell的重用機制,大頭針視圖也有重用機制
        static NSString *key = @"AnnotationIdentifier";
        MKAnnotationView *view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:key];
        if (!view) {
            view = [[MKAnnotationView alloc] initWithAnnotation:annotation
                                                reuseIdentifier:key];
        }
        //設置大頭針數據
        view.annotation = annotation;
        //自定義大頭針默認是NO,表示不能彈出視圖,這裏讓大頭針能夠點擊彈出視圖
        view.canShowCallout = YES;
        //設置大頭針圖標
        view.image = annotationLT.icon;
        //設置彈出視圖的左邊視圖
        UIImage *leftImage = [UIImage imageNamed:@"cafeIcon"];
        UIImageView *leftView = [[UIImageView alloc] initWithImage: leftImage];
        leftView.bounds = CGRectMake(0, 0, 50, 50);
        view.leftCalloutAccessoryView = leftView;
        //設置彈出視圖的右邊視圖
        UIImage *rightImage = [UIImage imageNamed:@"cafeRight"];
        UIImageView *rightView = [[UIImageView alloc] initWithImage: rightImage];
        rightView.bounds = CGRectMake(0, 0, 50, 50);
        view.rightCalloutAccessoryView = rightView;
        return view;
    }
    //返回nil,表示顯示默認樣式
    return nil;
}
複製代碼

改變默認樣式的大頭針視圖

###4、擴展--自定義大頭針彈出詳情視圖 若是你去關注下一些地圖應用,會發現他們的彈出視圖和咱們的徹底不同,那是怎麼實現的呢?

實際上那不是彈出視圖,那是個大頭針,只是這個大頭針作得和彈出視圖很像而已。

######實現思路:

  1. 當點擊普通的大頭針時,移除地圖上其餘的詳情大頭針,添加當前大頭針的詳情大頭針
  2. 當普通大頭針取消選中時,移除地圖上全部的詳情大頭針
  3. mapView:viewForAnnotation:方法中設置普通大頭針視圖和詳情大頭針視圖

######下面是實現的部分代碼【實現效果比較隨便,見諒】:

#pragma mark - 地圖控件代理方法
/* 顯示大頭針時調用,注意方法中的annotation參數是即將顯示的大頭針對象 */
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
    //因爲當前位置的標註也是一個大頭針,因此此時須要判斷,此代理方法返回nil使用默認大頭針視圖
    if ([annotation isKindOfClass:[LTAnnotation class]]) {
        static NSString *key1 = @"AnnotationKey1";
        MKAnnotationView *annotationView = [_mapView dequeueReusableAnnotationViewWithIdentifier:key1];
        //若是緩存池中不存在則新建
        if (!annotationView) {
            annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
                                                          reuseIdentifier:key1];
            annotationView.canShowCallout = NO;//不容許彈出視圖,但能夠被選中
        }
        //從新設置此類大頭針視圖的大頭針模型(由於有多是從緩存池中取出來的,位置是放到緩存池時的位置)
        annotationView.annotation = annotation;
        annotationView.image = ((LTAnnotation *)annotation).icon;//設置大頭針視圖的圖片
        return annotationView;
    }else if([annotation isKindOfClass:[LTCalloutAnnotation class]]){
        static NSString *key2 = @"AnnotationCallOutKey2";
        MKAnnotationView *calloutView = [_mapView dequeueReusableAnnotationViewWithIdentifier:key2];
        //若是緩存池中不存在則新建
        if (!calloutView) {
            calloutView = [[MKAnnotationView alloc] initWithAnnotation:annotation
                                                       reuseIdentifier:key2];
            calloutView.canShowCallout = NO;//不容許彈出視圖,但能夠被選中
        }
        //對於做爲彈出詳情視圖的自定義大頭針視圖無彈出交互功能,在其中能夠自由添加其餘視圖
        calloutView.annotation = annotation;
        //設置詳情大頭針的偏移位置
        calloutView.centerOffset = CGPointMake(-50, -80);
        [self calloutAddSubView:calloutView];
        return calloutView;
    } else {
        return nil;
    }
}
複製代碼

上面個人LTCalloutAnnotation和LTAnnotation其實是隻是類名不一樣而已,屬性都同樣。

#pragma mark 添加彈出視圖的子控件,這裏我就很隨便了,你能夠搞得好看點
- (void)calloutAddSubView:(MKAnnotationView *)calloutView
{
    //添加背景
    UIView *background = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 60)];
    background.backgroundColor = [UIColor whiteColor];
    background.layer.borderWidth = 5;
    background.layer.borderColor = [UIColor blueColor].CGColor;
    [calloutView addSubview:background];
    //添加圖片
    UIImage *image = [UIImage imageNamed:@"cafeRight"];
    UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
    imageView.frame = CGRectMake(5, 5, 50, 50);
    [calloutView addSubview:imageView];
    //添加一個紅色方塊
    UIView *subview = [[UIView alloc] initWithFrame:CGRectMake(60, 5, 35, 40)];
    subview.backgroundColor = [UIColor redColor];
    [calloutView addSubview:subview];
}

#pragma mark 選中大頭針時觸發
//點擊通常的大頭針KCAnnotation時添加一個大頭針做爲所點大頭針的彈出詳情視圖
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
    if ([view.annotation isKindOfClass:[LTAnnotation class]]) {
        LTAnnotation *annotation = view.annotation;
        //點擊一個大頭針時移除其餘彈出詳情視圖
        [self removeCalloutAnnotation];
        //添加詳情大頭針
        LTCalloutAnnotation *callout = [[LTCalloutAnnotation alloc] init];
        callout.icon = annotation.icon;
        callout.title = annotation.title;
        callout.subtitle = annotation.subtitle;
        callout.coordinate = annotation.coordinate;
        [self.mapView addAnnotation:callout];
    }
}
#pragma mark 取消選中時觸發
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view{
    [self removeCalloutAnnotation];
}
#pragma mark 移除所用詳情大頭針
-(void)removeCalloutAnnotation{
    [self.mapView.annotations enumerateObjectsUsingBlock:^(id obj,NSUInteger idx,BOOL *stop){
        if ([obj isKindOfClass:[LTCalloutAnnotation class]]) {
            [_mapView removeAnnotation:obj];
        }
    }];
}
複製代碼

自定義彈出視圖的效果圖

這個自定義彈出詳情視圖,我作的比較簡陋,我主要是爲了好說明具體是怎麼實現的,你能夠把彈出界面作的好看點,順便把一些大頭針視圖進行下封裝,那一切就很完美了,O(∩_∩)O哈!這種實現是很低效的,每次都須要遍歷全部的大頭針,從中找到詳情大頭針,須要優化的地方不少,能夠本身去想着優化。

#####若是有什麼意見請在下方評論區寫出來,求關注,求打賞,O(∩_∩)O哈!

相關文章
相關標籤/搜索