始めに
iOS標準の地図を提供するMapKitのMKMapViewで、
GoogleMapのようなダブルタップからの上下スライドでズームイン・アウトする機能を実装した。
単にズームイン・アウトをするだけなら単純だったのだが、
デフォルトで設定してあるダブルタップでのズームの機能を残すのに少し苦労した。
コード
import MapKit
class ViewController: UIViewController {
/* ドラッグの位置記憶用の変数 */
var dragPoint: CGPoint?
var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView = MKMapView(frame: view.bounds)
view.addSubview(mapView)
let doubleLongPress = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.doubleLongPress(_:)))
/* ダブルタップ後、即座にLongPress状態に移るように */
doubleLongPress.minimumPressDuration = 0
doubleLongPress.numberOfTapsRequired = 1
mapView.addGestureRecognizer(doubleLongPress)
doubleLongPress.delegate = self
/* MKMapViewの機能が実装してあるSubViewを引っ張ってきて、設定してあるDoubleTapGestureRecognizerにdelegateを設定する */
mapView.subviews[0].gestureRecognizers?.forEach({ (element) in
if let recognizer = (element as? UITapGestureRecognizer) where recognizer.numberOfTapsRequired == 2 {
element.delegate = self
}
})
}
}
extension ViewController: UIGestureRecognizerDelegate {
/* このzoomメソッドの実装は適当 */
func zoom(magnification: Double) {
var region = mapView.region
let span = region.span
region.span = MKCoordinateSpan(latitudeDelta: span.latitudeDelta * magnification, longitudeDelta: span.longitudeDelta * magnification)
mapView.setRegion(region, animated: false)
}
/* ダブルタップ → 上下動 で、ズームイン / アウト する (GoogleMap的な挙動) */
func doubleLongPress(recognizer: UILongPressGestureRecognizer) {
let state = recognizer.state
let location = recognizer.locationInView(recognizer.view)
switch state {
case .Began:
dragPoint = location
case .Changed:
/* 上に動いたか下に動いたか判断 */
let diffY = Double(location.y - dragPoint!.y)
let magnification = 1 - diffY * 0.01
self.zoom(magnification)
dragPoint = location
default:
break
}
}
/* MKMapViewに元から設定されているDoubleTapと、自分で設定したLongPressを同時に機能させる */
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
forced unwrapとかエラー処理とか設定する値のvalidationとかには適宜対応する。
ポイント
-
元から設定してあるDoubleTapのrecognizerを無理矢理引っ張ってくる
-
gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer)
のdelegateメソッドを実装して、
元から実装してあるDoubleTapと自分で設定したLongPressを同時に機能させる
これで、ダブルタップ → 上下スライド でのズームイン・アウトと単なるダブルタップでのズームが共存できるはず。
上下スライドを行った後で勝手にズームしないか心配だったが、その辺は都合よく動いた。
終わりに
iOS標準の地図にダブルタップ → 上下スライド でズームイン・アウトの機能が実装されていないのは特許の問題だろうか。
だとしたら勝手に実装したらまずい気もする。探しても実装した例が見つからなかったのはそのせいだろうか。とか思った。