[SwiftUI][MapKit] Map に Annotation を表示する方法

SwiftUI2021

     
⌛️ 3 min.
MapKit で遊んでみます その2 地図上に、追加情報を表示してみます。

環境&対象

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

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

前回まで

前回の記事はこちら
SwiftUI2021 [SwiftUI][MapKit] Map の使い方

できたことは以下です。
・SwiftUI で Map を使用して地図を表示した
・MKCoordinateRegion を使用して、地図に表示される領域を東京駅周辺に設定した

Map 上へ追加表示する準備

Map 上へ追加情報を表示するために必要となる要素を説明していきます。

MapAnnotationProtocol

Map 上に、追加情報(Annotation) として表示する要素が準拠すべき protocol です。

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

protocol として公開されていますが、実際にこの protocol に準拠するクラスを作るのではなく、すでに用意されている MapAnnotation/MapMarker を使用していきます。

MapPin という要素も用意されていましたが、iOS16/macOS13 で deprecated になりました。

MapMaker

MapMarker は、バルーン状のアイコンがでる要素です。

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

MapMarker を生成するときには、位置指定のために、CLLocationCoordinate2D が必要となります。
また、tint: で色を指定することでバルーンの色を変更することもできます。

MapMarker.init

init(
    coordinate: CLLocationCoordinate2D,
    tint: Color? = nil
)

MapAnnotation

MapAnnotation は、地図上の表示を カスタマイズするために用意された SwiftUI 向け要素です。

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

initializer は、以下のようになっています。

MapAnnotation.init

init(
    coordinate: CLLocationCoordinate2D,
    anchorPoint: CGPoint = CGPoint(x: 0.5, y: 0.5), @ViewBuilder content: () -> Content
)

coordinate で地図上の位置を、anchorPoint で表示要素のどこを 位置に合わせるかを設定することができます。
content がまさしく 表示要素を設定する箇所です。
Text で文字表示することも、Rectangle 等の図形要素を表示することもできます。

Map上への追加表示

準備ができたので、追加表示を実装していきます。

今回は、東京駅の場所にバルーンを表示。その後、カスタムビューを表示してみます。

SwiftUI の View である Map でも位置指定で追加表示 (Annotation) をするときには、
Map を生成するときの以下の initializer の 5、6番目の引数である annotationItems: と annotationContent: を使用して表示要素の追加を行います。

Map.init

init(
    coordinateRegion: Binding,
    interactionModes: MapInteractionModes = .all,
    showsUserLocation: Bool = false,
    userTrackingMode: Binding? = nil,
    annotationItems: Items,
    annotationContent: @escaping (Items.Element) -> Annotation
) where Content == _DefaultAnnotatedMapContent, Items : RandomAccessCollection, Annotation : MapAnnotationProtocol, Items.Element : Identifiable

items

items は、追加表示を行う情報 のコレクションです。ランダムアクセスできるコレクションであればOKですが、要素は、Identifiable であることが必要です。

Identifiable であることが必要なので、以下のような struct を作成して使用します。

struct MyAnnotation: Identifiable {
    let id: UUID = UUID()
    let location: CLLocationCoordinate2D
}

location には、追加情報を表示したい対象の位置情報を設定することを想定しています。

そのほか、名前などの追加表示したい情報があれば、この struct に追加して、表示するときにその情報を参照して表示要素を追加していくことになります。

annotationContent

annotationContent では、先の追加情報が渡されるので、表示したい情報を View として返します。
追加情報に保存されている情報から View を構築する必要があるので、表示に使用する情報は、この場合では、MyAnnotation に保存されていることが必要です。

Map上への追加表示 実装

最初に、既存の要素 MapMarker を使った実装を行い、その後、MapAnnotation に切り替えて、自由な(?) 表示を行います。

MapMarker を使った実装

MapMarker は、CLCoordinate2D と Color を指定すると生成することができるので、使い方も簡単です。

東京駅の場所に、グリーンのバルーン(MapMarker)を表示します。

GreenBaloon

annotationContent の closure 内で、MyAnnotation に保持している location を使って、MapMarker を生成しています。(色のグリーンは、固定です)

コードは以下です。

//
//  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 MyAnnotation: Identifiable {
    let id: UUID = UUID()
    let location: CLLocationCoordinate2D
}

struct ContentView: View {
    let annotations: [MyAnnotation] = [MyAnnotation(location: tokyoStation)]

    @State private var mapCenter = MKCoordinateRegion(center: tokyoStation,
                                                      latitudinalMeters: 1000,
                                                      longitudinalMeters: 1000)
    
    var body: some View {
        VStack {
            Text("Tokyo Station")
            Map(coordinateRegion: $mapCenter,
                annotationItems: annotations, annotationContent: { annotationItem in
                return MapMarker(coordinate: annotationItem.location,
                                 tint: .green)
            })
        }
        .padding()
    }
}

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

MapAnnotation を使った実装

MapAnnotation を使って、表示をカスタマイズする時には、もう少し複雑になります。

MapAnnotation 自身で、View を返す必要があります。
以下の例では、Text に背景色/境界色を設定した View を返しています。

NameWithBorder
//
//  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 MyAnnotation: Identifiable {
    let id: UUID = UUID()
    let location: CLLocationCoordinate2D
}

struct ContentView: View {
    let annotations: [MyAnnotation] = [MyAnnotation(location: tokyoStation)]

    @State private var mapCenter = MKCoordinateRegion(center: tokyoStation,
                                                      latitudinalMeters: 1000,
                                                      longitudinalMeters: 1000)

    var body: some View {
        VStack {
            Text("Tokyo Station")
            Map(coordinateRegion: $mapCenter,
                annotationItems: annotations, annotationContent: { annotationItem in
                return MapAnnotation(coordinate: annotationItem.location,
                                     anchorPoint: CGPoint(x: 0.5, y: 0.5),
                                     content: {
                    Text("Tokyo Station")
                        .padding(4)
                        .background{ RoundedRectangle(cornerRadius: 5).fill(Color.white.opacity(0.5)) }
                        .overlay{ RoundedRectangle(cornerRadius: 5).stroke(Color.green, lineWidth: 5) }
                })
            })
        }
        .padding()
    }
}

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

まとめ

MapKit を使った Map 表示に Annotation を追加

MapKit を使った Map 表示に Annotation を追加
  • Map 生成時に、Annotation データを指定する
  • バルーン表示向けに、MapMarker が用意されている
  • カスタマイズした表示が行いたいときは、MapAnnotation を使用する

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

SwiftUI おすすめ本

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

SwiftUI ViewMastery

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

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

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

超便利です

SwiftUIViewsMastery

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

SwiftUI 徹底入門

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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です