xyk blog

最近は iOS 開発の記事が多めです。

MKMapView 上のタップした地点を中心にして正方形を描く

検証環境:
Xcode 12
Swift 5.3

f:id:xyk:20201111134019j:plain

前回は地図上(MKMapView)に円を描画したが、今回は正方形の矩形を描画してみる。

まずMapKitをインポートしておく。

import MapKit
  • MKMapView にUITapGestureRecognizerを追加してタップを検出する。
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(mapTapped(_:)))
mapView.addGestureRecognizer(tapGesture)
  • この時呼び出すmapTappedメソッドを定義する。
    前回の円の場合はMKCircleだったが、今回はMKPolygonオブジェクトを作成してMKMapView#addOverlayで追加する。
    MKPolygon には4つの緯度経度を追加する。
@objc func mapTapped(_ sender: UITapGestureRecognizer) {
    if sender.state == .ended {
        let tapPoint = sender.location(in: mapView)
        // タップした座標(CGPoint)を緯度経度(CLLocationCoordinate2D)に変換する
        let center = mapView.convert(tapPoint, toCoordinateFrom: view)
        // 100m四方のRegionを作成
        let region = MKCoordinateRegion(center: center, latitudinalMeters: 100, longitudinalMeters: 100)
        
        // 4点の緯度経度を算出する
        let leftTop = CLLocationCoordinate2D(latitude: center.latitude - region.span.latitudeDelta / 2, longitude: center.longitude - region.span.longitudeDelta / 2)
        let rightTop = CLLocationCoordinate2D(latitude: center.latitude + region.span.latitudeDelta / 2, longitude: center.longitude - region.span.longitudeDelta / 2)
        let rightBottom = CLLocationCoordinate2D(latitude: center.latitude + region.span.latitudeDelta / 2, longitude: center.longitude + region.span.longitudeDelta / 2)
        let leftBottom = CLLocationCoordinate2D(latitude: center.latitude - region.span.latitudeDelta / 2, longitude: center.longitude + region.span.longitudeDelta / 2)
        
        var coordinates = [leftTop, rightTop, rightBottom, leftBottom]
        let polygon = MKPolygon(coordinates: &coordinates, count: coordinates.count)
        mapView.addOverlay(polygon)
    }
}

MKCoordinateSpan の latitudeDelta, longitudeDelta について。
latitudeDelta は対象マップ領域の北端と南端の緯度の差、
longitudeDelta は対象マップ領域の東端と西端の経度の差となる。
緯度の center の latitude から latitudeDelta / 2 北にずれれば表示範囲の北端が、南にずれれば表示範囲の南端が求まる。
経度についても同様。

  • MKMapViewDelegateデリゲートを使う準備
mapView.delegate = self
  • デリゲートメソッドmapView(_:rendererFor:)を実装して、MKPolygonオブジェクトを生成する。
    このデリゲートメソッドはMKMapView#addOverlayで追加された時に呼ばれる。
extension ViewController: MKMapViewDelegate {

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        
        if let polygone = overlay as? MKPolygon {
            let renderer = MKPolygonRenderer(polygon: polygone)
            renderer.strokeColor = UIColor.red // 枠線の色
            renderer.fillColor = UIColor.red.withAlphaComponent(0.2) // 内側の色
            renderer.lineWidth = 2 // 枠線の太さ
            return renderer
        }
        
        return MKOverlayRenderer()
    }
}