MapKit Framework!!
iOS 9 週連続 Bootcamp 5週目
Hirai Yuki @ Classmethod, Inc.
自己紹介
• 平井 祐樹 @ クラスメソッド株式会社
• iOSアプリエンジニア
• 最近はRuby on Rails
• http://dev.classmethod.jp/author/hirai-yuki/
• https://github.com/hirai-yuki
iOS 9 で追加された
MapKit の新機能
MapKit の新機能
• Flyoverでマップを表示できる
• ピンの色をカスタマイズできる
• 吹き出しをカスタマイズできる
• スケールバーを表示できる
• コンパスを表示できる
• 交通状況を表示できる
• 乗換案内機能をサポート
• CLGeocoder/MKLocalSearch で Time zone をサポート
地味だー
MapKit Framework の
使い方について iOS 9 での
変更点を(少し)踏まえて
解説します!
受託あるある
店舗マップ画面が欲しい!
店舗マップ画面の仕様
• マップは標準(2D)地図と航空写真(Flyover)を切り替えられるようにする
• コンパス・スケールバーをマップに表示する
• 店舗を表すピンをマップに表示する
• 店舗ピンはお店のロゴマークで
• ピンがタップされたら吹き出しに店舗名と店舗画像を表示する
• マップの初期表示位置は店舗ピンをすべて表示する
• 現在位置から店舗までの経路案内を行う
こんな感じ
ソースコード
• https://github.com/hirai-yuki/ShopMapSample
店舗マップ画面の仕様
• マップは標準(2D)地図と航空写真(Flyover)を切り替えられるようにする
• コンパス・スケールバーをマップに表示する
• 店舗を表すピンをマップに表示する
• 店舗ピンはお店のロゴマークで
• ピンがタップされたら吹き出しに店舗名と店舗画像を表示する
• マップの初期表示位置は店舗ピンをすべて表示する
• 現在位置から店舗までの経路案内を行う
MKMapType
Satellite HybridStandard
MKMapType
• Standard
• Satellite
• Hybrid
• SatelliteFlyover <- New!
• HybridFlyover <- New!
SatelliteFlyover
HybridFlyover
• ラベルも表記
MKMapType
self.mapView.mapType = MKMapTypeHybridFlyover;
店舗マップ画面の仕様
• マップは標準(2D)地図と航空写真(Flyover)を切り替えられるようにする
• コンパス・スケールバーをマップに表示する
• 店舗を表すピンをマップに表示する
• 店舗ピンはお店のロゴマークで
• ピンがタップされたら吹き出しに店舗名と店舗画像を表示する
• マップの初期表示位置は店舗ピンをすべて表示する
• 現在位置から店舗までの経路案内を行う
コンパスを表示する
• showsCompass <- New!
スケールバーを表示する
• showsScale <- New!
交通状況の表示
• showsTrafics <- New!
• 日本未対応っぽい
店舗マップ画面の仕様
• マップは標準(2D)地図と航空写真(Flyover)を切り替えられるようにする
• コンパス・スケールバーをマップに表示する
• 店舗を表すピンをマップに表示する
• 店舗ピンはお店のロゴマークで
• ピンがタップされたら吹き出しに店舗名と店舗画像を表示する
• マップの初期表示位置は店舗ピンをすべて表示する
• 現在位置から店舗までの経路案内を行う
店舗ピンの表示
1. 店舗用注釈クラスを作成する(注釈 = ピン)
2. データを準備する
3. 店舗用注釈ビューを作成する
注釈オブジェクト
• MKAnnotaion プロトコルに準拠したオブジェクト
• 地図座標/タイトル/サブタイトルを保持する
• 上記以外の情報が不要なら MKPointAnnotation を
使う
• そうでないなら MKAnnotation に準拠したクラスを
定義する
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface CLMShopAnnotation : NSObject <MKAnnotation>
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, readonly, copy, nullable) NSString *title;
@property (nonatomic, readonly, nullable) UIImage *image;
- (nonnull instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate
title:(nullable NSString *)title
image:(nullable UIImage *)image;
@end
1. 店舗用注釈クラスを作成する
1. 店舗用注釈クラスを作成する
2. データを準備する
// MKShopAnnotationインスタンスの配列を生成
NSArray *shops = @[
[[CLMShopAnnotation alloc] initWithCoordinate:CLLocationCoordinate2DMake(<緯度>, <経度>)
title:@"クラスメソッド本店"
image:[UIImage imageNamed:@"cm"]],
・・・
];
// MKShopAnnotationインスタンスの配列をマップビューに追加
[self.mapView addAnnotations:shops];
3. 店舗用注釈ビューを作成する
• MKAnnotationView またはその派生クラス
• マップビューのデリゲートメソッドを定義して注釈ビュー
を返す
• 標準的なピン:MKPinAnnotationView
• 独自の画像を使う:MKAnnotationView
• もっとやる:MKAnnotationView のサブクラスを定義
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
} else if ([annotation isKindOfClass:[CLMShopAnnotation class]]) {
CLMShopAnnotation *shopAnnotation = (CLMShopAnnotation *)annotation;
MKAnnotationView *annotationView =
[mapView dequeueReusableAnnotationViewWithIdentifier:@"ShopAnnotation"];
if (annotationView) {
annotationView.annotation = shopAnnotation;
} else {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:shopAnnotation
reuseIdentifier:@"ShopAnnotation"];
}
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:@"shop_pin"];
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.rightCalloutAccessoryView = rightButton;
annotationView.detailCalloutAccessoryView =
[[UIImageView alloc] initWithImage:shopAnnotation.image];
return annotationView;
}
return nil;
}
3. 店舗用注釈ビューを作成する
detailCalloutAccessoryView <- New!
店舗マップ画面の仕様
• マップは標準(2D)地図と航空写真(Flyover)を切り替えられるようにする
• コンパス・スケールバーをマップに表示する店舗を表すピンをマップに
表示する
• 店舗ピンはお店のロゴマークで
• ピンがタップされたら吹き出しに店舗名と店舗画像を表示する
• マップの初期表示位置は店舗ピンをすべて表示する
• 現在位置から店舗までの経路案内を行う
初期表示位置を指定する
• - showAnnotations:animate: を使用
• 引数で指定したピンがすべて表示されるよ
う表示位置と縮尺を設定してくれる
[self.mapView showAnnotations:self.shops animated:YES];
regionを指定する場合
• MKCoordinateRegion構造体で表される
• 縮尺の指定に慣れが必要
MKCoordinateRegion
typedef struct {
CLLocationCoordinate2D center;
MKCoordinateSpan span;
} MKCoordinateRegion;
中心位置
???
MKCoordinateSpan
• ある地点において可視である地図上の範囲
• 単位:度、分、秒
• 大きなスパン:広い範囲(低い拡大率)
• 小さなスパン:狭い範囲(高い拡大率)
• 緯度1度 ≒ 111km、経度1度 = 緯度によって変わる
• MKCoordinateRegionMakeWithDistance で「m」でも作成できる
• マップビューでは指定されたスパンが収まるようなズームレベルを暗黙的に設
定し、regionを調節する
MKCoordinateSpan
self.mapView.region =
MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2DMake(<緯度>, <経度>), 100, 100);
iPhone 6s plus iPhone 5s iPhone 4s
店舗マップ画面の仕様
• マップは標準(2D)地図と航空写真(Flyover)を切り替えられるようにする
• コンパス・スケールバーをマップに表示する
• 店舗を表すピンをマップに表示する
• 店舗ピンはお店のロゴマークで
• ピンがタップされたら吹き出しに店舗名と店舗画像を表示する
• マップの初期表示位置は店舗ピンをすべて表示する
• 現在位置から店舗までの経路案内を行う
経路案内
• 2地点間の経路探索にMKDirectionsを使用
• 得られた経路をマップに描画
MKDirectionsによる経路探索
• 出発地(現在地)と目的地のMKMapItemイン
スタンスを生成
MKMapItem *source = [MKMapItem mapItemForCurrentLocation];
MKPlacemark *placemark = [[MKPlacemark alloc]
initWithCoordinate:annotation.coordinate
addressDictionary:nil];
MKMapItem *destination = [[MKMapItem alloc] initWithPlacemark:placemark];
MKDirectionsによる経路探索
• 出発地と目的地のMKMapItemインスタンスを用
いてMKDirectionsRequestインスタンスを生成
MKDirectionsRequest *request = [MKDirectionsRequest new];
request.transportType = MKDirectionsTransportTypeAutomobile;
request.source = source;
request.destination = destination;
MKDirectionsによる経路探索
• 作成したMKDirectionsRequestインスタンスを引数にセットして
MKDirectionsインスタンスを生成
• - calculateDirectionsWithCompletionHandler:メソッドを実行
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse
*response, NSError *error) {
・・・
}];
経路の描画
• MKRouteのpolylineプロパティ
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError
*error) {
・・・
[self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
・・・
}];
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolyline *polyline = overlay;
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:polyline];
renderer.lineWidth = 3.0;
renderer.strokeColor = [UIColor colorWithRed:255/255.0 green:81/255.0 blue:81/255.0
alpha:1.0];
return renderer;
}
return nil;
}
まとめ
• Flyoverはおもしろそう!
• 早く日本も乗換案内と交通状況を対応してほしい
References
• 位置情報とマッププログラミングガイド
• https://developer.apple.com/jp/documentation/
LocationAwarenessPG.pdf
• AlohaYos/LocalSearch
• https://github.com/AlohaYos/LocalSearch
• 地図ライブラリ
• http://www.asahi-net.or.jp/~YY8A-IMI/20040913/ipad/
map.htm
ご清聴ありがとうございました

Mapkitframework io9week