SwiftUI で Apple 地図 ( Maps ) を実装する方法 – ピン を 複数 立てる方法 等 –

スマホ アプリ の強みとして「 地図 の表示」や 「場所に ピン を立てること」 が挙げられると思います。 SwiftUI を用いて実装できる 地図 サービス には いくつかの種類がありますが 本記事では Apple 純正の Map を取り上げ、 SwiftUI を用いて 以下を実装する方法について説明していきます。

  • 緯度経度情報を基に 地図 を表示する方法
  • 1 つの ピン を立てる方法
  • 複数 ピン を立てる方法
Xcode: 13.1
iOS: 14.5
Swift: 5

緯度経度を基に 地図 を表示

まずはじめに 緯度経度を基に地図を表示してみたいと思います。 Apple Developer サイト の情報 に従って Apple Park の地図を表示してみます。

引数説明
center中心地点を CLLocationCoordinate2D を 緯度経度 を基に指定
latitudinalMeters地図に表示する 南北方向の広さを メートル で指定
longitudinalMeters地図に表示する 東西方向の広さを メートル で指定
  • Map オブジェクト には 上述した region 変数を引数に指定
import MapKit

struct AppleParkMap: View {
   
   @State private var region = MKCoordinateRegion(
       center: CLLocationCoordinate2D(latitude: 37.334_900,
                                      longitude: -122.009_020),
       latitudinalMeters: 750,
       longitudinalMeters: 750
   )
 
   var body: some View {
       Map(coordinateRegion: $region)
   }
}

ContentView で この View (AppleParkMap) を呼び出す形にして ビルド してみると以下のような結果となります。 コード 上は 東西 南北 共に 750 m としていますが、縦長の画面に表示するため、 南北 750 m として表示されます。

なお 以下のように 東西方向 50 m とすると、東西 50 m の地図が表示されます。 指定した サイズ を 表示領域に最大限表示するようなかたちになっています。

    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.334_900,
                                       longitude: -122.009_020),
        latitudinalMeters: 750,
        longitudinalMeters: 50
    )

地図上 に ピン を追加

続いて、 先程作成した地図に Apple Developer サイト の情報を参考に ピン を追加してみたいと思います。

Annotation Items の定義

Map に対して annotationItems として、 以下のように定義した MapAnnotationProtocolで Map ピン を指定する必要があります。 init() の中に記載された通り、 引数に 緯度, 経度 の数値を指定することで MapAnnotationProtocol 型を生成することができます。

struct IdentifiablePlace: Identifiable {
    let id: UUID
    let location: CLLocationCoordinate2D
    init(id: UUID = UUID(), lat: Double, long: Double) {
        self.id = id
        self.location = CLLocationCoordinate2D(
            latitude: lat,
            longitude: long)
    }
}

Annotation Items を引数に指定し Map に ピン を追加

上記を annotationItems 引数に追加するように 先程の View を以下のように修正します。

struct AppleParkMap: View {
    let place: IdentifiablePlace

    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.334_900,
                                       longitude: -122.009_020),
        latitudinalMeters: 750,
        longitudinalMeters: 750
    )
    
    
    var body: some View {
        Map(coordinateRegion: $region, annotationItems: [place]) {
            place in MapPin(coordinate: place.location, tint: Color.purple)
        }
    }
}

同時に ContentView からの呼び出し方法も修正していきます。 先程の例では AppleParkMap View には引数が不要でしたが、 今回は Apple Park の緯度, 経度 を指定することで Apple Park に ピン を立てたいと思います。

struct ContentView: View {
    var body: some View {
        AppleParkMap(place: IdentifiablePlace(lat: 37.334_900, long: -122.009_020))
    }
}

ピン を 追加した Map

以下の通り Apple Park に 紫色の ピン を立てることができました。


Map に ピン を複数 追加

本記事の最後に 地図上に ピン を複数 追加する方法を紹介します。 今まで作成してきた Apple Park を中心とした地図に 以下 2つ の ピン を 追加してみたいと思います。

  • Steve Jobs Theater
  • Apple Park Tantau Reception

ピン の 緯度, 経度 定義

以下のように MapAnnotationProtocol 型 として定義した IdentifiablePlace オブジェクト として 今回追加するピンの情報を登録します。

    @State private var places: [IdentifiablePlace] = [
        // Steve Jobs Theater
        IdentifiablePlace(lat: 37.331_01,  long: -122.007_45),
        // Apple Park Tantau Reception
        IdentifiablePlace(lat: 37.332_44,  long: -122.006_14)
    ]

なお、緯度経度 情報は Google Map 上で右クリックするなどで 以下のように知ることができます。

Map 描画部分実装

Map 描画部分は 以下のような引数を用います。

引数説明
coordinateRegionMKCoordinateRegion で指定した 緯度経度地点 と その範囲
annotationItemsannotation として表示する アイテム
ここでは 緯度経度情報を含む IdentifiablePlace オブジェクト の配列
annotationContentクロージャー としてannotation アイテム を生成する処理

AppleParkMap の body を以下のように修正します。 今回は ピン の色を赤にしてみます。

    var body: some View {
        Map(coordinateRegion: $region,
            annotationItems: places,
            annotationContent: { place in
                MapPin(coordinate: place.location, tint: Color.red)
            }
        )
    }

複数 ピン を追加した Map

ビルド すると 以下のように 2 つの場所に ピン が追加された地図が表示されます。


まとめ

  • MapKit をインポートし Map を利用可能に
  • 地図は CLLocationCoordinate2D で中心地点を決め、 あわせて 表示範囲を メートル で指定
  • ピン を立てるときは MapAnnotationProtocol 型 で ピン の位置を定義
  • ピン を複数立てるときは Map の 引数として以下を指定
    • annotationItems: 立てたい ピン の位置情報を MapAnnotationProtocol 型 で 配列として定義
    • annotationContent: クロージャー の中で MapPin 生成処理 を記述

関連記事

参照情報

Apple Developer Site

Map

How do I add pins and other annota…


サンプルコード ( SwiftUI )

1 つの ピン を Map に表示するサンプル

//
//  ContentView.swift
//

import SwiftUI

struct ContentView: View {
    var body: some View {
        AppleParkMap(place: IdentifiablePlace(lat: 37.334_900, long: -122.009_020))
    }
}
//
//  AppleParkMap.swift
//

import SwiftUI
import MapKit

struct IdentifiablePlace: Identifiable {
    let id: UUID
    let location: CLLocationCoordinate2D
    init(id: UUID = UUID(), lat: Double, long: Double) {
        self.id = id
        self.location = CLLocationCoordinate2D(
            latitude: lat,
            longitude: long)
    }
}

struct AppleParkMap: View {
    let place: IdentifiablePlace

    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.334_900,
                                       longitude: -122.009_020),
        latitudinalMeters: 750,
        longitudinalMeters: 750
    )
    
    
    var body: some View {
        Map(coordinateRegion: $region, annotationItems: [place]) {
            place in MapPin(coordinate: place.location, tint: Color.purple)
        }
    }
}

複数 ピン を Map に表示するサンプル

//
//  ContentView.swift
//

import SwiftUI

struct ContentView: View {
    var body: some View {
        AppleParkMap()
    }
}
//
//  AppleParkMap.swift
//

import SwiftUI
import MapKit

struct IdentifiablePlace: Identifiable {
    let id: UUID
    let location: CLLocationCoordinate2D
    init(id: UUID = UUID(), lat: Double, long: Double) {
        self.id = id
        self.location = CLLocationCoordinate2D(
            latitude: lat,
            longitude: long)
    }
}

struct AppleParkMap: View {
    @State private var places: [IdentifiablePlace] = [
        // Steve Jobs Theater
        IdentifiablePlace(lat: 37.330_93,  long: -122.007_46),
        // Apple Park Tantau Reception
        IdentifiablePlace(lat: 37.332_44,  long: -122.006_14)
    ]

    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.334_900,
                                       longitude: -122.009_020),
        latitudinalMeters: 750,
        longitudinalMeters: 750
    )
    
    var body: some View {
        Map(coordinateRegion: $region,
            annotationItems: places,
            annotationContent: { place in
                MapPin(coordinate: place.location, tint: Color.red)
            }
        )
    }
}