地図を表示する (5.0以降のみ)
iOSでMapKitを使って地図表示を行うのはとても簡単です。5.0以降ならAndroidのMapActivityのように、位置情報を取得して、現在位置のトラッキングも勝手にやってくれるような機能まで入っています。 地図の出し方なんて今更な気もするのですが、iOSでちゃんとした地図アプリを書くのは初めてなので、実装にあたって調べたことをメモしておきます。
5.1.1と 6.0以降で中身が劇的に変化しちゃいましたが、frameworkレベルでは別に大差ありません…いや6.0で経路情報がもらえるんでしたっけ?普通に地図を出す方法は一緒ということで、深く考えないようにしておきます。
余談ですが、 6.0以降専用のGoogle Maps API for iOSも研究してみましたが、Google Maps Android API v2 と同時期にリリースしてきただけあって、かなり良いできです。今のうちに研究だけでもしておいた方が良いかもしれません。
centerCoordinate
表示中の地図の中心座標
typedef struct {
CLLocationDegrees latitude;
CLLocationDegrees longitude;
} CLLocationCoordinate2D;
緯度、経度をそれぞれ度で指定する
mapType
地図の種類
- MKMapTypeStandard - 道路地図
- MKMapTypeSatellite - 衛星画像
- MKMapTypeHybrid - 衛星+道路
region / setRegion: animated:
地図の表示範囲。中心と、縦横を度で指定する。
typedef struct {
CLLocationCoordinate2D center;
MKCoordinateSpan span;
} MKCoordinateRegion;
typedef struct {
CLLocationDegrees latitudeDelta;
CLLocationDegrees longitudeDelta;
} MKCoordinateSpan;
設定したspanが設定されるわけではなく、適切な値に丸められる。どんな値になるのかを予め計算したいときは、
- (MKCoordinateRegion)regionThatFits:(MKCoordinateRegion)region
を使って計算する。
showsUserLocation
地図上にユーザーの現在位置を表示するかどうか。これがYESの間、位置情報の取得が行われ、userLocationに設定される。
userTrackingMode / setUserTrackingMode:animated:
ユーザーの現在位置を追跡するかどうか。
- MKUserTrackingModeNone - なし
- MKUserTrackingModeFollow - 現在位置を地図中心にする
- MKUserTrackingModeFollowWithHeading - 現在位置を地図中心にし、方向にあわせて回転させる
Follow系のモードに設定した際には、ズームレベルが勝手に調整される。また、Followモードはユーザーが画面をある程度ドラッグすると解除される。
userLocation
showUserLocationがYESの時に、ユーザーの現在位置が格納される。MKUserLocationオブジェクト。
delegate
地図表示中のイベントのDelegate。定義しとくとよさげなのは以下の4つ。
- (void)mapViewDidFailLoadingMap:(MKMapView )mapView withError:(NSError )error
ネットワークエラー等で、地図データ読み込みに失敗した時に呼ばれる。
- (void)mapView:(MKMapView )mapView didUpdateUserLocation:(MKUserLocation )userLocation
shorUserLocation=YESの時、位置情報が更新される度に呼ばれる。
- (void)mapView:(MKMapView )mapView didFailToLocateUserWithError:(NSError )error
位置情報の取得が許可されていない等で、測位できなかった時に呼ばれる。
- (void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated
userTrackingModeが変更された時に呼ばれる。
初期表示位置の調整
userTrackingModeがFollowになっている場合、centerもspanもMap側に主導権を握られているのでたいしたことはできない。Followはしたいが、勝手にズームを変更されたくないという場合には、Noneで現在位置を表示しつつ、Delegateの位置情報更新メソッドでcenterLocationを設定するような処理を追加する必要がある。
ちなみに、私はviewDidLoadでこんな処理を書いています。(CoreLocationに直近の位置情報があればそれを中心として表示)
- (void)viewDidLoad
{
[super viewDidLoad];
_mapView.delegate = self;
_mapView.showsUserLocation = YES;
MKCoordinateRegion region;
region.span.latitudeDelta = 0.01;
region.span.longitudeDelta = 0.01;
if(_mapView.userLocation){
CLLocation* userloc = _mapView.userLocation.location;
if(userloc){
region.center.latitude = userloc.coordinate.latitude;
region.center.longitude = userloc.coordinate.longitude;
}
}else{
region.center.latitude = 35;
region.center.longitude = 135;
}
[_mapView setRegion:region animated:NO];
_mapView.userTrackingMode = MKUserTrackingModeFollow;
}
測位可能かどうかの判定
測位サービスが使用可能かどうかを調査するメソッドは以下
[CLLocationManager locationServicesEnabled]
ただし、これは位置情報サービスが onになっているかどうかを返すだけで、アプリに対して許可されているかどうかはわからない。そちらを知るためには、実際に位置情報を取得してみて、Delegateでエラーが返ってくるかどうかを確認するしかない。
とりあえずここまで
Annotation(画面上に置くPinと注釈)とOverlayはまた別の機会にでも。