【Swift】Map Kit Viewの使い方。長押しした位置にピンを刺す。(Swift 2.1、XCode 7.2)
タップしてピンを刺すとは
前回の記事で、MKMapView(以下、マップビュー)の地図上に刺さっているピンをドラッグ&ドロップで移動させる方法について説明した。⇒「記事」
ピンを移動するのではなく、ピンを刺す場所をピンポイントで指定したいことがある。そこで本記事では画面をタップした場所にピンを刺す方法について説明する。
説明の前に、タップ位置を検出するためにTap Gesture Recognizer(以下、タップ検知)、Long Press Gesture Recognizer(以下、長押し検知)のどちらを使うのがいいかを考える。
タップ検知を使う場合、ダブルタップで地図を拡大したときに以下の動画のようにピンの位置が変わってしまうので、ダブルタップはピンに影響しない作りにする必要がある。
また、ピンをタップして吹き出しを表示したときに、以下の動画のように新しいピンが出現してしまうので、ピンをタップしたときもピンに影響しない作りにする必要がある。
上記を考慮すると、タップ検知ではなく長押し検知を使ったほうが実装がシンプルになりそうだ。よって、本記事では長押し検知でピンを刺す方法を採用する。
以降の手順は「Map Kit Viewの使い方」の続きから行うので、実装を試してみる人は先に読んでおくことをお勧めする。
ジェスチャーリコグナイザーを配置する
ジェスチャーリコグナイザーをマップビューに配置する(下図赤矢印)。すると、部品一覧に下図黄緑枠のジェスチャーリコグナイザーが追加される。
紫枠のアシスタントエディタボタンを押してViewController.swiftを開く。Ctrlキーを押しながらジェスチャーリコグナイザーをドラッグ&ドロップでソースコードまで運んで吹き出しの設定画面を表示する(青矢印)。
Connectionに「Action」、Nameに「pressMap」、Typeに「UILongPressGestureRecognizer」を入力し、Connectボタンを押す。これで長押しのイベントをソースコードで受けれるようになった。
ピンを刺す処理を実装する
ViewController.swiftを以下のコードに変更する。「マップビュー長押し時の呼び出しメソッド」で、タップ位置を座標(緯度経度)に変換し、それをもとにアノテーションを作成してビューに追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
// // ViewController.swift // import UIKit import MapKit class ViewController: UIViewController,MKMapViewDelegate { @IBOutlet weak var testMapView: MKMapView! //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //中心座標 let center = CLLocationCoordinate2DMake(35.0, 140.0) //表示範囲 let span = MKCoordinateSpanMake(1.0, 1.0) //中心座標と表示範囲をマップに登録する。 let region = MKCoordinateRegionMake(center, span) testMapView.setRegion(region, animated:true) //デリゲート先に自分を設定する。 testMapView.delegate = self } //マップビュー長押し時の呼び出しメソッド @IBAction func pressMap(sender: UILongPressGestureRecognizer) { //マップビュー内のタップした位置を取得する。 let location:CGPoint = sender.locationInView(testMapView) if (sender.state == UIGestureRecognizerState.Ended){ //タップした位置を緯度、経度の座標に変換する。 let mapPoint:CLLocationCoordinate2D = testMapView.convertPoint(location, toCoordinateFromView: testMapView) //ピンを作成してマップビューに登録する。 let annotation = MKPointAnnotation() annotation.coordinate = CLLocationCoordinate2DMake(mapPoint.latitude, mapPoint.longitude) annotation.title = "ピン" annotation.subtitle = "\(annotation.coordinate.latitude), \(annotation.coordinate.longitude)" testMapView.addAnnotation(annotation) } } //アノテーションビューを返すメソッド func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? { let testView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: nil) //吹き出しを表示可能にする。 testView.canShowCallout = true return testView } } |
以下は実際のプレイ動画
ピンの場所を移動する
上記コードは長押しした場所にピンを無制限に追加していく実装である。次は、地図上のピンは1個だけで、長押しした場所にピンを移動する作りにしてみよう。
ViewController.swiftを以下のコードに変更する。クラス変数としてピンを保持し、「マップビュー長押し時の呼び出しメソッド」が呼び出されたら、座標とサブタイトルを更新している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
// // ViewController.swift // import UIKit import MapKit class ViewController: UIViewController,MKMapViewDelegate { @IBOutlet weak var testMapView: MKMapView! let annotation = MKPointAnnotation() //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //中心座標 let center = CLLocationCoordinate2DMake(35.0, 140.0) //表示範囲 let span = MKCoordinateSpanMake(1.0, 1.0) //中心座標と表示範囲をマップに登録する。 let region = MKCoordinateRegionMake(center, span) testMapView.setRegion(region, animated:true) //ピンを作成してマップビューに登録する。 annotation.coordinate = CLLocationCoordinate2DMake(35.0, 140.0) annotation.title = "ピン" annotation.subtitle = "\(annotation.coordinate.latitude), \(annotation.coordinate.longitude)" testMapView.addAnnotation(annotation) //デリゲート先に自分を設定する。 testMapView.delegate = self } //マップビュー長押し時の呼び出しメソッド @IBAction func pressMap(sender: UILongPressGestureRecognizer) { //マップビュー内のタップした位置を取得する。 let location:CGPoint = sender.locationInView(testMapView) if (sender.state == UIGestureRecognizerState.Ended){ //タップした位置を緯度、経度の座標に変換する。 let mapPoint:CLLocationCoordinate2D = testMapView.convertPoint(location, toCoordinateFromView: testMapView) //ピンの座標とサブタイトルを更新する。 annotation.coordinate = CLLocationCoordinate2DMake(mapPoint.latitude, mapPoint.longitude) annotation.subtitle = "\(annotation.coordinate.latitude), \(annotation.coordinate.longitude)" } } //アノテーションビューを返すメソッド func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? { let testView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: nil) //吹き出しを表示可能にする。 testView.canShowCallout = true return testView } } |
以下は実際のプレイ動画