[SwiftUI][MapKit] Map の使い方

SwiftUI2021

     
MapKit で遊んでみます

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Monterey 13 Beta5
  • Xcode 14.0 Beta5
  • iOS 16.0 beta

Map 周辺概要

MapKit の Map/地図 を表示する View です。

以前は、UIView/NSView を継承する MKMapView を使って表示する必要がありましたが、iOS14/macOS12 以降では Map という View を使用して、地図を表示することができます。

Apple のドキュメントは、こちら

Map 周辺基礎知識

実際に使い始める前に、MapKit を使用する時に使う 主要な要素を簡単に説明しておきます。

CLLocationCoordinate2D

CLLocationCoordinate2D は、地球上の点を 緯度・経度を使用して指定するための struct です。
CL は "Core Location" から来ています。

Apple のドキュメントは、こちら

なお、緯度/経度は、英語ではそれぞれ latitude/longitude です。

Swift では、CLLocationDegrees 型を使用して表現されます。実際には、CLLocationDegrees は Double が typealias されたものです。

Degree とついていることからわかりますが、角度を表す値です。単位は 度 です。(同様に角度を扱う関数 sin/cos/tan で使われているのはラジアンであり、単位が異なります。)
緯度経度で指定する時に 一般的に 度の補助単位として 分・秒を使用することもできますが、CLLocationDegrees では、度に対して、Double を使って 少数を 指定することで指定します。分/秒 を使用して設定することはできません。必要に応じて自分で換算することが必要となります。

赤道は、緯度 0 度となる基準であり、グリニッジ天文台(正確には 旧グリニッジ天文台跡)が 経度 0 度の基準になります。

例えば、東京駅は、緯度:35.6809591 度 経度:139.7673068 度 の位置にあります。

latitude は、90 ~ -90 が、longitude は、180 ~ -180 をそれぞれの値域としてもちます。
latitude が正であれば 北半球、負であれば 南半球を意味します。
なお、360度が周期であることを利用して、例えば、270 を -90 の替わりにするというような表現は受け付けられません。

MEMO
Apple のドキュメントには、latitude の値域は、-90 〜 90 であると記載されています。ところが、実際に境界値である 90 を指定して表示しようとすると CLLocationCoordinate2DIsValid では、 valid と判定されますが、(SwiftUI の View である) Map ではエラーが発生しました。
ギリギリ(?)手前の値 89.999 であれば動作しましたので、SwiftUI の Map での表示に使用するときは -90 < x < 90 という開区間を値域として持っていると考えた方が良さそうです。

MKCoordinateRegion

地図上の1点だけでなく、特定の範囲を指定するための型も用意されています。

Apple のドキュメントは、こちら

CLLocationCoordinate2D を使用して 中心を設定します。

範囲の指定方法には、大きく2つ 以下の方法があります。

・具体的な距離で指定する方法
・範囲を角度で指定する方法

具体的な距離で指定する方法

緯度経度の方向それぞれにどのくらいの範囲かを距離で指定します。単位は、メートルです。

型に、CLLocationDistance ですが、Double の typealias です。

具体的な距離を指定する時には、以下の initializer を使用して MKCoordinateRegion を生成します。


init(
    center centerCoordinate: CLLocationCoordinate2D,
    latitudinalMeters: CLLocationDistance,
    longitudinalMeters: CLLocationDistance
)

範囲を角度で指定する方法

角度を使って範囲を指定する時には、MKCoordinateSpan という型を使用して指定します。

Apple のドキュメントは、こちら

MKCoordinateSpan は、緯度経度それぞれの角度を情報として持ちます。型は CLLocationDegrees です(typealias された Double です)。なお、1度は、約 111 km (69マイル)に相当します。

角度情報を持つ MKCoordinateSpan を使う時には、以下の initializer を使用して MKCoordinateRegion を生成します。


init(
    center: CLLocationCoordinate2D,
    span: MKCoordinateSpan
)

Map を表示

詳細の使い方を確認する前に、とりあえず 地図を表示してみます。

Map ビューは、その名の通り、Map ですが、使用するためには、地図としてどの領域を表示するかを指定する必要があります。

Map では、表示地域を指定するために2つの方法が良いされています。

・MKCoordinateRegion
  緯度経度をベースとした領域指定
・MKMapRect
  メルカトル図法を使って作成された(2次元の)地図上での領域を指定

以降では、MKCoordinateRegion を使っていきます。

MapKit のコンセプトは、こちらを参照してください。

先ほど例示した東京駅の位置情報を使って、表示してみます。

シンプルに使う場合 Map に渡す引数は、Binding<MKCoordinateRegion> だけです。
Map は、ユーザーが操作することで、最初に表示された位置から 移動や拡大縮小ができます。そのため、表示領域情報は Binding で渡すようになっています。このようになっていることで、ユーザーの操作によって変更された表示領域がコード側からもわかるようになっています。

TokyoStation

//
//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2022/08/23
//  © 2022  SmallDeskSoftware
//

import SwiftUI
import MapKit

let tokyoStation = CLLocationCoordinate2D(latitude: 35.680_9591, longitude: 139.767_3068)

struct ContentView: View {
    @State private var mapCenter = MKCoordinateRegion(center: tokyoStation,
                                                     latitudinalMeters: 1000,
                                                     longitudinalMeters: 1000)
    
    var body: some View {
        VStack {
            Text("Tokyo Station")
            Map(coordinateRegion: $mapCenter)
        }
        .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

オプション

非常にシンプルに使っていますが、Map を生成する時に以下のようなオプションを指定することもできます。

interactionModes

Map ビューがユーザー操作を受け付けるか、受け付けるならばどの操作かを指定することができます。

・all : すべて(pan, zoom いずれも可能)
・pan :pan 操作のみ
・zoom: zoom 操作のみ

Apple のドキュメントは、こちら

showUserLocation/userTrackingMode

Bool 型 の showUserLocation に true を設定するとユーザーの位置情報が表示されます。(ただし、事前に ユーザーからの許諾が必要です。)

showUserLocation が true であるときに、設定された Binding<MapUserTrackingMode>? を渡すことで、ユーザーの位置情報更新を反映するかどうかを設定できます。

なお、MapUserTrackingMode には、以下の値があります。
・follow
・none

annotationItems/annotationContent

地図上に、さまざまな情報(annotation)を付与するための引数が、annotationItems/annotationContent です。

annotationItems が情報の配列、annotationContent を使うことで情報からどのように表示するかを設定することができます。

次回以降の記事で、この引数を使って、地図上に情報を表示していきます。

まとめ

MapKit を使った Map 表示

MapKit を使った Map 表示
  • 位置情報と範囲を与えると Map で地図を表示できる
  • 位置情報は、緯度経度で指定する
  • 範囲は、距離・角度の2通りの指定方法がある

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

SwiftUI おすすめ本

SwiftUI を理解するには、以下の本がおすすめです。

SwiftUI ViewMastery

SwiftUI で開発していくときに、ViewやLayoutのための適切なmodifierを探すのが大変です。
英語での説明になってしまいますが、以下の”SwiftUI Views Mastery Bundle"という本がビジュアル的に確認して探せるので、便利です。

英語ではありますが、1ページに コードと画面が並んでいるので、非常にわかりやすいです。

View に適用できる modifier もわかりやすく説明されているので、ビューの理解だけではなく、どのような装飾ができるかも簡単にわかります。

超便利です

SwiftUIViewsMastery

販売元のページは、こちらです。

SwiftUI 徹底入門

# SwiftUI は、毎年大きく改善されていますので、少し古くなってしまいましたが、いまでも 定番本です。

コメントを残す

メールアドレスが公開されることはありません。