Posted at

MKMapView のユーザートラッキングモードを標準マップアプリと同等に実装する

More than 5 years have passed since last update.

iOS 8 がそろそろ出る、というタイミングでずいぶんレガシーな話ですいません。iOS 5 の頃からある MKUserTrackingMode をどう扱えば標準マップアプリと同等になるか、の実装手順メモです。ここはアプリによって違うことはあまりなく、だいたいワンパターンだと思うので。


ユーザートラッキングモードとは

ユーザートラッキングモードというのは、標準マップアプリにも Google Maps アプリにもついている、

trackingmode.jpg

こういうボタンで順番に切り替わるもので、MKMapView では以下の3種が定義されてます。



  • MKUserTrackingModeNone ・・・ユーザーの現在位置に応じてマップを更新しない


  • MKUserTrackingModeFollow ・・・ユーザーの現在位置に応じてマップを更新する


  • MKUserTrackingModeFollowWithHeading ・・・ユーザーの現在位置と 進行方向 に応じてマップを更新する

ちなみに上の写真は自分の進行方向に応じて地図の向きが変わる MKUserTrackingModeFollowWithHeading です。


ボタン画像変更メソッド

モードが切り替わったときにボタンの画像を切り替えるメソッドを用意します。

- (void)updateUserTrackingModeBtn:(MKUserTrackingMode)mode {

NSString *filename = nil;

switch (mode) {
case MKUserTrackingModeNone:
default:
filename = @"tracking_no";
break;
case MKUserTrackingModeFollow:
filename = @"tracking_follow";
break;
case MKUserTrackingModeFollowWithHeading:
filename = @"tracking_heading";
break;
}

[self.userTrackingModeBtn setImage:[UIImage imageNamed:filename]
forState:UIControlStateNormal];
}


ボタンのアクション

モード切り替えボタンのアクションとして、MKMapView の userTrackingMode プロパティを順番に変更し、それに応じてボタンの画像を変更するメソッドを用意します。

- (IBAction)userTrackingModeBtnTapped:(id)sender {

MKUserTrackingMode mode;

switch (self.mapView.userTrackingMode) {
case MKUserTrackingModeNone:
default:
mode = MKUserTrackingModeFollow;
break;
case MKUserTrackingModeFollow:
mode = MKUserTrackingModeFollowWithHeading;
break;
case MKUserTrackingModeFollowWithHeading:
mode = MKUserTrackingModeNone;
break;
}

[self updateUserTrackingModeBtn:mode];
[self.mapView setUserTrackingMode:mode animated:YES];
}


初期設定

viewDidLoad あたりで、初期値にしておきます。

[self.mapView setUserTrackingMode:MKUserTrackingModeNone animated:YES];

[self updateUserTrackingModeBtn:MKUserTrackingModeNone];


ユーザー操作による変更

標準マップアプリを見てると、少しマップを動かすと、そのとき MKUserTrackingMode が MKUserTrackingModeFollow であっても MKUserTrackingModeFollowWithHeading であっても、MKUserTrackingModeNone強制的に戻されることがわかります。

これを実現するのに、最初は自分で mapView:regionDidChangeAnimated: でマップ移動をフックしてモード切り替えするのかなーと思ったのですがそうではなく、 MKMapView内部で勝手に切り替えてくれている ようです。

というわけで、 mapView:didChangeUserTrackingMode:animated: でモード切り替えをフックし、ボタン画像をそれに適したものに変更すればOK。

- (void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated {

[self updateUserTrackingModeBtn:mode];
}