天天看點

【原】iOS學習48地圖

一、地圖的簡介

 在移動網際網路時代,移動app能解決使用者的很多生活瑣事,比如   

  導航:去任意陌生的地方

  周邊:找餐館、找酒店、找銀行、找電影院

  手機軟體:微信搖一搖、QQ附近的人、微網誌、支付寶等

 在上述應用中,都用到了地圖和定位功能,在iOS開發中,要想加入這兩大功能,必須基于兩個架構進行開發

  MapKit :用于地圖展示

  CoreLocation :用于地理定位

二、地圖定位(CoreLocation架構,地理編碼與反地理編碼)

 1、CoreLocation架構的使用

  • 導入架構  (iOS5之後不再需要)
  • 導入頭檔案
#import <CoreLocation/CoreLocation.h>      
  • CoreLocation架構使用須知

        CoreLocation 架構中所有資料類型的字首都是CL

        CoreLocation 中使用 CLLocationManager 對象來做使用者定位 

 2、CLLocationManager的常用操作(詳細使用說明見注釋)

// 開始使用者定位
- (void)startUpdatingLocation;
// 停止使用者定位
- (void) stopUpdatingLocation;

// 每隔多少米定位一次
@property(assign, nonatomic) CLLocationDistance distanceFilter;
// 定位精确度(越精确就越耗電)
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;

// 當調用了startUpdatingLocation方法後,就開始不斷地定位使用者的位置,中途會頻繁地調用下面的代理方法
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations; // 參數locations中的元素對象是CLLocation對象,是一系列的位置資訊

// 當定位失敗的時候,會調用下面的代理方法
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(nullable CLRegion *)region withError:(NSError *)error;      

  CLLocationAccuracy 是一個枚舉值

/*
最佳導航
  kCLLocationAccuracyBestForNavigation 
最精準
     kCLLocationAccuracyBest;
10米
     kCLLocationAccuracyNearestTenMeters; 
百米
     kCLLocationAccuracyHundredMeters; 
千米
     kCLLocationAccuracyKilometer; 
3千米
     kCLLocationAccuracyThreeKilometers;     
*/      

 3、CLLocation

  CLLocation用來表示某個位置的地理資訊,比如經緯度、海拔等等

// 經緯度
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;

// 海拔
@property(readonly, nonatomic) CLLocationDistance altitude;

// 路線,航向(取值範圍是0.0° ~ 359.9°,0.0°代表正北方向)
@property(readonly, nonatomic) CLLocationDirection course;

// 行走速度(機關是m/s)
@property(readonly, nonatomic) CLLocationSpeed speed;

// 此方法可以計算2個位置(CLLocation)之間的距離
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location      

 4、CLLocationCoordinate2D

  CLLocationCoordinate2D 是一個用來表示經緯度的結構體,定義如下

typedef struct {
    CLLocationDegrees latitude; // 緯度
    CLLocationDegrees longitude; // 經度
} CLLocationCoordinate2D;      

  一般用 CLLocationCoordinate2DMake 函數來建立 CLLocationCoordinate2D

 5、實作定位的步驟

  • 第一步:初始化定位管理器
self.manager = [[CLLocationManager alloc] init];      
  • 第二步:進行隐私的判斷和授權    

  1> 進行定位服務是否開啟的判斷       

   若 locationServicesEnabled 為 NO,就跳轉到隐私界面進行設定

  2> 進行版本判斷(iOS8.0前後的定位方式不一樣)擷取版本數:[[[UIDevice currentDevice] systemVersion] integerValue]

  3> iOS8.0之後授權的操作

            ① 判斷授權狀态:authorizationStatus

                五種狀态枚舉值

                    kCLAuthorizationStatusNotDetermined: 使用者尚未做出決定是否啟用定位服務

                    kCLAuthorizationStatusRestricted: 沒有獲得使用者授權使用定位服務,可能使用者沒有自己禁止通路授權

                    kCLAuthorizationStatusDenied:使用者已經明确禁止應用使用定位服務或者目前系統定位服務處于關閉狀态

                    kCLAuthorizationStatusAuthorizedAlways: 應用獲得授權可以一直使用定位服務,即使應用不在使用狀态(常用)

                    kCLAuthorizationStatusAuthorizedWhenInUse: 使用此應用過程中允許通路定位服務(常用)

            ② 在授權請求之前需要在infoPlist檔案中設定 NSLocationUsageDescription 允許定位内容

                authorizationStatus 為 kCLAuthorizationStatusAuthorizedWhenInUse 時使用NSLocationWhenInUseUsageDescription 進行設定

                authorizationStatus 為 kCLAuthorizationStatusAuthorizedAlways 時使用 NSLocationAlwaysUsageDescription 進行設定

      一旦使用者選擇了 "Don’t Allow",意味着你的應用以後就無法使用定位功能為了嚴謹起見,最好在使用定位功能之前判斷目前應用的定位功能是否可用,也就是我的 1> 進行定位服務是否開啟的判斷            

     ③ 請求授權

                requestWhenInUseAuthorization要和infoPlist檔案中的比對(NSLocationWhenInUseUsageDescription)

                requestAlwaysAuthorization要和infoPlist檔案中的比對(NSLocationAlwaysUsageDescription)

// 第二步:進行隐私的判斷和授權
    // 進行隐私的判斷
    if (![CLLocationManager locationServicesEnabled]) { 
        NSLog(@"是否前往隐私進行設定允許定位");
    }

    // 進行版本的判斷
    if ([[[UIDevice currentDevice] systemVersion] integerValue] >= 8.0) {
        // 根據狀态進行授權
        if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
            
            // 請求授權
            [self.manager requestWhenInUseAuthorization];
       
       [self.manager requestWhenInUseAuthorization]; 

        }
   }      

  注意:從iOS 7之後,蘋果在保護使用者隐私方面做了很大的加強,以下操作都必須經過使用者準許授權:

   ① 要想獲得使用者的位置和通路使用者的通訊錄、月曆、相機、相冊等等都需要使用者來手動授權。

   ② 當想通路使用者的隐私資訊時,系統會自動彈出一個對話框讓使用者授權

  • 第三步:設定管理器的代理和相關屬性
// 第三步:設定管理器的代理和相關屬性
    self.manager.delegate = self;
    
    // 設定精度
    self.manager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    
    // 設定最小更新距離
    self.manager.distanceFilter = 10;      

  CLLocationManagerDelegate

  定位成功後開始更新位置資訊,隻要移動的距離大于設定最小更新距離時也開始走這個方法:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{  
    // 擷取最後一次的位置
    CLLocation *location = locations.lastObject;
    // 擷取位置坐标
    CLLocationCoordinate2D coordinate = location.coordinate;
    // 列印經緯度,longitude 經度 latitude 緯度
    NSLog(@"經度:%f, 緯度:%f, 海拔:%f, 航向:%f, 行走速度:%f", coordinate.longitude, coordinate.latitude, location.altitude, location.course, location.speed);
    
    // 為了節省電源,如果不使用定位,需要把定位關閉
    [self.manager stopUpdatingLocation];
}      

   定位失敗

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"定位失敗");
}      

 6、地理編碼與地理反編碼

  • 使用CLGeocoder可以完成"地理編碼"和"反地理編碼"

   地理編碼:根據給定的地名,獲得具體的位置資訊(比如經緯度、位址的全稱等)

   反地理編碼:根據給定的經緯度,獲得具體的位置資訊

  • 具體方法:
// 地理編碼方法
- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;

// 反地理編碼方法
- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;      
  • CLGeocodeCompletionHandler

  當地理編碼/反地理編碼完成時,就會調用 CLGeocodeCompletionHandler,頭檔案聲明:

typedef void (^CLGeocodeCompletionHandler)(NSArray<CLPlacemark *> *placemarks, NSError *error);      

  block包含2個參數

   error:當編碼出錯時(比如編碼不出具體的資訊),2其錯誤資訊會包含在error中

   placemarks:裡面裝着 CLPlacemark 對象

  • CLPlacemark

  CLPlacemark的字面意思是地标,封裝詳細的位址位置資訊,相關屬性:

// 地理位置
@property (nonatomic, readonly) CLLocation *location;

// 區域
@property (nonatomic, readonly) CLRegion *region;

// 詳細的位址資訊
@property (nonatomic, readonly) NSDictionary *addressDictionary;

// 位址名稱
@property (nonatomic, readonly) NSString *name;

// 地點名稱 
@property (nonatomic, readonly) NSString *locality;      

 7、詳細執行個體代碼

【原】iOS學習48地圖
【原】iOS學習48地圖
#import "ViewController.h"

// 第一步:引入庫的頭檔案
#import <CoreLocation/CoreLocation.h>

@interface ViewController () <CLLocationManagerDelegate>

// CoreLocation架構中的CLLocationManager用于管理定位的管理器

/// 定位管理器
@property (nonatomic, strong) CLLocationManager *manager;

/// 編碼和反編碼類
@property (nonatomic, strong) CLGeocoder *geocoder;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    // 定位的步驟
    
    // 第一步:初始化定位管理器
    self.manager = [[CLLocationManager alloc] init];
    
    // 第二步:進行隐私的判斷和授權
    // 進行隐私的判斷
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"是否前往隐私進行設定允許定位");
    }

    // 進行版本的判斷
    if ([[[UIDevice currentDevice] systemVersion] integerValue] >= 8.0) {
        
        // 根據狀态進行授權     
        if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
            // 請求授權
            [self.manager requestWhenInUseAuthorization];
        }
    }
    
    // 第三步:設定管理器的代理和相關屬性
    self.manager.delegate = self;
    
    // 設定精度
    self.manager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    
    // 設定最小更新距離
    self.manager.distanceFilter = 10;
    
    // 第四步:開啟定位
    [self.manager startUpdatingLocation];
    
    /***********************編碼和反編碼**********************/
    
    // 初始化對象
    self.geocoder = [[CLGeocoder alloc] init];
    
    // 根據地名擷取經緯度
//    [self getCoordinateByAddress:@"中國山西省朔州市右玉縣新城鎮綠源小區"];
    
    // 編譯和反編譯不能同時走,設定不同的按鈕來分别實作
    
    // 根據經緯度反編譯取出地名
//    [self getAddressByLongitude:112.4750 Latitude:39.98];
    
    // 計算兩點之間的距離
//    [self distanceForDeuce];
}

#pragma mark - 計算兩點之間的距離
- (void)distanceForDeuce
{
    // 建立位置
    CLLocation *locationBeijing = [[CLLocation alloc] initWithLatitude:40 longitude:116];
    CLLocation *locationYouyu = [[CLLocation alloc] initWithLatitude:39.98 longitude:112.47];
    
    // 計算距離
    CLLocationDistance distance = [locationBeijing distanceFromLocation:locationYouyu];
    
    NSLog(@"%f公裡", distance / 1000);
}


#pragma mark - 根據經緯度反編譯取出地名
- (void)getAddressByLongitude:(CLLocationDegrees)longitude
                     Latitude:(CLLocationDegrees)latitude
{
    // 反編碼
    
    // 建立CLLocation
    CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
    
    [self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        NSDictionary *dict = placemarks.firstObject.addressDictionary;
        NSLog(@"反編碼地理位置資訊:%@", dict);
    }];
}

#pragma mark - 根據地名擷取經緯度
- (void)getCoordinateByAddress:(NSString *)address
{
    [self.geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        // 根據傳回的地标,取出起一個位置(地标位置很多)
        CLPlacemark *mark = placemarks.firstObject;
        
        // 根據地标得到location
        CLLocation *location = mark.location;
        // 根據地标擷取地區
        CLRegion *region = mark.region;
        
        // 擷取字典資訊
        NSDictionary *addressDict = mark.addressDictionary;
        
        NSLog(@"location = %@\n region = %@\n addressDict = %@", location, region, addressDict);
        
        // 根據具體的需求進行選擇輸出
//        NSString *name=placemark.name;//地名
//        NSString *thoroughfare=placemark.thoroughfare;//街道
//        NSString *subThoroughfare=placemark.subThoroughfare; //街道相關資訊,例如門牌等
//        NSString *locality=placemark.locality; // 城市
//        NSString *subLocality=placemark.subLocality; // 城市相關資訊,例如标志性建築
//        NSString *administrativeArea=placemark.administrativeArea; // 州
//        NSString *subAdministrativeArea=placemark.subAdministrativeArea; //其他行政區域資訊
//        NSString *postalCode=placemark.postalCode; //郵編
//        NSString *ISOcountryCode=placemark.ISOcountryCode; //國家編碼
//        NSString *country=placemark.country; //國家
//        NSString *inlandWater=placemark.inlandWater; //水源、湖泊
//        NSString *ocean=placemark.ocean; // 海洋
//        NSArray *areasOfInterest=placemark.areasOfInterest; //關聯的或利益相關的地标
        
    }];
}

#pragma mark - CLLocationManagerDelegate的代理方法

// 定位成功後開始更新位置資訊,隻要移動的距離大于設定最小更新距離時也開始走這個方法
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    // 擷取最後一次的位置
    CLLocation *location = locations.lastObject;
    // 擷取位置坐标
    CLLocationCoordinate2D coordinate = location.coordinate;
    // 列印經緯度,longitude 經度 latitude 緯度
    NSLog(@"經度:%f, 緯度:%f, 海拔:%f, 航向:%f, 行走速度:%f", coordinate.longitude, coordinate.latitude, location.altitude, location.course, location.speed);
    
    // 為了節省電源,如果不使用定位,需要把定位關閉
    [self.manager stopUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"定位失敗");
}

@end      

View Code

三、地圖顯示(MapKit架構)

 1、MapKit架構的使用

  • 導入架構(iOS5之後不再需要程式員自己導入)
  • 導入主頭檔案
#import <MapKit/MapKit.h>      
  • MapKit架構使用須知

  MapKit架構中所有資料類型的字首都是MK

  MapKit有一個比較重要的UI控件:MKMapView,專門用于地圖顯示

 2、跟蹤顯示使用者的位置

  設定MKMapView的userTrackingMode屬性可以跟蹤顯示使用者的目前位置

   MKUserTrackingModeNone :不跟蹤使用者的位置

   MKUserTrackingModeFollow :跟蹤并在地圖上顯示使用者的目前位置

   MKUserTrackingModeFollowWithHeading :跟蹤并在地圖上顯示使用者的目前位置,地圖會跟随使用者的前進方向進行旋轉

  下圖是跟蹤效果:

   藍色發光圓點就是使用者的目前位置,專業術語叫做 "大頭針"

 3、地圖的類型

  可以通過設定MKMapView的mapType設定地圖類型(mapViewType是枚舉類型)

MKMapTypeStandard // 普通地圖(左圖)
MKMapTypeSatellite // 衛星雲圖 (中圖)
MKMapTypeHybrid // 普通地圖覆寫于衛星雲圖之上(右圖)
MKMapTypeSatelliteFlyover NS_ENUM_AVAILABLE(10_11, 9_0) // 地形和建築物的三維模型
MKMapTypeHybridFlyover NS_ENUM_AVAILABLE(10_11, 9_0) // 顯示道路和附加元素的Flyover      

 4、MKMapView的代理

  • MKMapView可以設定一個代理對象 MKMapViewDelegate,用來監聽地圖的相關行為,常見的代理方法有:
// 一個位置更改預設隻會調用一次,不斷監測使用者的目前位置時每次都會調用這個方法,把使用者的最新位置(userLocation參數)傳進來.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;

// 地圖的顯示區域即将發生改變的時候調用
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;

// 地圖的顯示區域已經發生改變的時候調用
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;      
  • MKUserLocation其實是個大頭針模型,包括以下屬性:
// 顯示在大頭針上的标題
@property (nonatomic, copy) NSString *title;

// 顯示在大頭針上的子标題
@property (nonatomic, copy) NSString *subtitle;

// 地理位置資訊(大頭針釘在什麼地方)
@property (readonly, nonatomic) CLLocation *location;      

 5、設定地圖的顯示

  • 通過MKMapView的下列方法,可以設定地圖顯示的位置和區域
// 設定地圖的中心點位置
@property (nonatomic) CLLocationCoordinate2D centerCoordinate;

-(void)setCenterCoordinate: (CLLocationCoordinate2D)coordinate animated:(BOOL)animated;

@property (nonatomic) MKCoordinateRegion region;
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;      
  • MKCoordinateRegion是一個用來表示區域的結構體,定義如下:
typedef struct {
    CLLocationCoordinate2D center; // 區域的中心點位置
   MKCoordinateSpan span; // 區域的跨度
} MKCoordinateRegion;      
  • MKCoordinateSpan的定義:
typedef struct {
    CLLocationDegrees latitudeDelta; // 緯度跨度
    CLLocationDegrees longitudeDelta; // 經度跨度
} MKCoordinateSpan;      

 6、大頭針

  • 建立一個大頭針模型類,繼承 NSObject,遵循 MKAnnotation 協定就是一個大頭針!
#import <Foundation/Foundation.h>

#import <MapKit/MapKit.h>

@interface MyAnnotation : NSObject <MKAnnotation>

// 重寫協定中的三個屬性:coordinate(标記位置)、title(标題)、subtitle(子标題)

/// 坐标
@property (nonatomic) CLLocationCoordinate2D coordinate;

/// 标題
@property (nonatomic, copy) NSString *title;

/// 子标題
@property (nonatomic, copy) NSString *subtitle;

@end      
  • 大頭針的基本操作
// 添加一個大頭針
- (void)addAnnotation:(id <MKAnnotation>)annotation;

// 添加多個大頭針
- (void)addAnnotations:(NSArray *)annotations;

// 移除一個大頭針
- (void)removeAnnotation:(id <MKAnnotation>)annotation;

// 移除多個大頭針
- (void)removeAnnotations:(NSArray *)annotations;      

 7、簡單執行個體代碼

【原】iOS學習48地圖
【原】iOS學習48地圖
#import "ViewController.h"

// 地圖使用的空間
#import <MapKit/MapKit.h>

#import <CoreLocation/CoreLocation.h>

#import "MyAnnotation.h"

@interface ViewController () <MKMapViewDelegate>

/// 定位管理器
@property (nonatomic, strong) CLLocationManager *locationManager;

/// 顯示地圖的視圖
@property (nonatomic, strong) MKMapView *mapView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    // 建立地圖視圖
    [self createMapView];
}

#pragma mark - 建立地圖視圖
- (void)createMapView
{
    // 建立地圖,并添加到目前視圖上
    self.mapView = [[MKMapView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    
    [self.view addSubview:self.mapView];
    
    // 設定代理
    self.mapView.delegate = self;
    
    // 定位
    self.locationManager = [[CLLocationManager alloc] init];
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"目前裝置定位不可用");
    }
    if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
        [self.locationManager requestWhenInUseAuthorization];
    }
    
    // 設定地圖的定位追蹤的模式
    self.mapView.userTrackingMode = MKUserTrackingModeFollow;
    // 設定地圖的顯示類型
    self.mapView.mapType = MKMapTypeStandard;
    
    // 添加大頭針
    [self addAnnotation];
    
}

#pragma mark - 添加大頭針
- (void)addAnnotation
{
    // 設定位置北京
    CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(40, 116);
    MyAnnotation *annotation = [[MyAnnotation alloc] init];
    annotation.coordinate = location1;
    annotation.title = @"北京";
    annotation.subtitle = @"一個古老的城市";
    
    // 設定位置右玉
    CLLocationCoordinate2D location2 = CLLocationCoordinate2DMake(39.98, 112.47);
    MyAnnotation *annotation2 = [[MyAnnotation alloc] init];
    annotation2.coordinate = location2;
    annotation2.title = @"右玉";
    annotation2.subtitle = @"生我養我的地方";
    
    // 大連
    CLLocationCoordinate2D location3 = CLLocationCoordinate2DMake(38.92, 121.62);
    MyAnnotation *annotation3 = [[MyAnnotation alloc] init];
    annotation3.coordinate = location3;
    annotation3.title = @"大連";
    annotation3.subtitle = @"一個喝啤酒吃蛤蜊的城市";
    
    NSArray *annotationArray = @[annotation, annotation2, annotation3];
    
    [self.mapView addAnnotations:annotationArray];
}

#pragma mark - 代理方法
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    NSLog(@"%@", userLocation);
}

@end      

四、自定義大頭針

  很多情況下,需要自定義大頭針的顯示樣式,比如顯示一張圖檔

 1、設定MKMapView的代理

  實作下面的代理方法,傳回大頭針控件

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation; // 根據傳進來的(id <MKAnnotation>)annotation參數建立并傳回對應的大頭針控件      

  代理方法的使用注意

   如果傳回nil,顯示出來的大頭針就采取系統的預設樣式

   辨別使用者位置的藍色發光圓點,它也是一個大頭針,當顯示這個大頭針時,也會調用代理方法

   是以,需要在代理方法中厘清楚(id <MKAnnotation>)annotation參數代表自定義的大頭針還是藍色發光圓點

 2、MKAnnotationView

  地圖上的大頭針控件是 MKAnnotationView,MKAnnotationView 的屬性:

// 大頭針模型
@property (nonatomic, strong) id <MKAnnotation> annotation;

// 顯示的圖檔
@property (nonatomic, strong) UIImage *image;

// 是否顯示标注
@property (nonatomic) BOOL canShowCallout;

// 标注的偏移量
@property (nonatomic) CGPoint calloutOffset;

// 标注右邊顯示什麼控件
@property (strong, nonatomic) UIView *rightCalloutAccessoryView;

// 标注左邊顯示什麼控件
@property (strong, nonatomic) UIView *leftCalloutAccessoryView;      

 3、MKPinAnnotationView

  MKPinAnnotationView 是 MKAnnotationView 的子類

  MKPinAnnotationView 比 MKAnnotationView 多了2個屬性:

// 大頭針顔色
@property (nonatomic) MKPinAnnotationColor pinColor;

// 大頭針第一次顯示時是否從天而降
@property (nonatomic) BOOL animatesDrop;      

 4、執行個體代碼

#pragma mark - 實作自定義大頭針的代理方法
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    // 判斷是否是目前自定義大頭針類
    if ([annotation isKindOfClass:[MyAnnotation class]]) {
        
        // 先定義一個重用辨別(和cell一樣)
        static NSString *identifiter = @"AnnotationOne";
        
        MKAnnotationView *annotationView = [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifiter];
        
        if (annotationView == nil) {
            
            annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifiter];
            
            // 允許使用者互動
            annotationView.canShowCallout = YES;
            // 設定詳情和大頭針的頭偏移量
            annotationView.calloutOffset = CGPointMake(0, 1);
            // 設定詳情的左視圖
            annotationView.leftCalloutAccessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1.jpg"]];
        }
        
        // 修改大頭針視圖
        annotationView.annotation = annotation;
        // 一定要指派
        annotationView.image = ((MyAnnotation *)annotation).image;
        
        return annotationView;
        
    } else {
        return nil;
    }
}      

繼續閱讀