今回の動作確認環境: Xcode 7.2 + Swift 2.1.1 + 実機 iPhone 6 + iOS 9.2

Swift + MapKit で地図にピンを降らせるアニメーション

  • ピンが上から降ってくるアニメーションをするためには MKMapViewDelegate と MKPinAnnotationView を使う。
  • 長押しの処理には UILongPressGestureRecognizer を使う。
  • 自動的にフキダシを表示するには MKMapKit.selectAnnotation を使う。

Xcode で新規に Single View Application のプロジェクトを作成して、以下のサンプルコードを ViewController.swift にコピペして、実行するだけでOK。


//
//  ViewController.swift
//

import UIKit
import MapKit

class ViewController: UIViewController, MKMapViewDelegate {
    
    // 地図
    private var myMapView: MKMapView?
    
    // ピン
    private var myPin: MKPointAnnotation?
    
    override func viewDidLoad() {
        
        super.viewDidLoad()
        
        // 地図
        myMapView = ViewController.createMapView(self.view, delegate: self)
        ViewController.setLongPressGesture(myMapView!, parentView: self)
        self.view.addSubview(myMapView!)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    private static func createMapView(parentView: UIView, delegate: MKMapViewDelegate) -> MKMapView {
        
        // MKMapView の生成
        let mapView = MKMapView()
        
        // MapView のサイズを指定
        mapView.frame = parentView.bounds
        
        // MKMapView に Delegate を設定
        mapView.delegate = delegate
        
        // 中心点の緯度経度(名古屋駅)
        let lat: CLLocationDegrees = 35.1707223
        let lon: CLLocationDegrees = 136.882136
        let coordinate: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, lon)
        
        // 縮尺
        let latDist : CLLocationDistance = 100
        let lonDist : CLLocationDistance = 100
        
        // Region を生成
        let region: MKCoordinateRegion =
        MKCoordinateRegionMakeWithDistance(coordinate, latDist, lonDist);
        
        // MKMapView に反映
        mapView.setRegion(region, animated: true)
        
        return mapView
    }

    // 長押しジェスチャーの設定
    private static func setLongPressGesture(mapView: MKMapView, parentView: UIViewController) {
        let lpg = UILongPressGestureRecognizer()
        lpg.addTarget(parentView, action: "onLongPress:")
        mapView.addGestureRecognizer(lpg)
    }
    
    // 長押しの際の処理
    func onLongPress(sender: UILongPressGestureRecognizer) {
        
        // 長押しを認識開始したとき以外は処理しない
        if (sender.state != .Began) {
            return
        }
        
        // 長押しした場所を取得
        let location = sender.locationInView(self.myMapView)
        
        // 長押しした場所の緯度・経度に変換
        let pos:CLLocationCoordinate2D = self.myMapView!.convertPoint(location, toCoordinateFromView: self.myMapView!)
        
        //ピンを生成
        let newPin = MKPointAnnotation()
        newPin.coordinate  = pos
        newPin.title       = "長押しした場所"
        newPin.subtitle    = "緯度,経度: " + pos.latitude.description + "," + pos.longitude.description
        
        // 古いピンを削除
        if let pin = self.myPin {
            self.myMapView!.removeAnnotation(pin)
        }
        
        // 新しいピンを追加
        self.myPin = newPin
        self.myMapView!.addAnnotation(self.myPin!)
        
        // ピンが表示されたら、自動的にフキダシを表示する
        self.myMapView!.selectAnnotation(self.myPin!, animated: true)
    }
    
    // ピンが表示される前にコールされる関数
    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {

        if annotation is MKUserLocation {
            return nil
        }

        // ピンのビューがすでに作成されていたら再利用する
        let reuseId = "pin"
        var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView

        if pinView == nil {
            pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
            // ピンが上から降ってくるアニメーションをセット
            pinView?.animatesDrop = true
            // フキダシを表示可能に
            pinView?.canShowCallout = true
        } else {
            pinView?.annotation = annotation
        }
        
        return pinView
    }

}

tags: Swift map mapkit

Posted by NI-Lab. (@nilab)