TechSwiftUIJapanese

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

Tech

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

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

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

[ads]

まずはじめに 緯度経度を基に地図を表示してみたいと思います。 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
    )
[ads]

地図上 に ピン を追加

[ads]

続いて、 先程作成した地図に 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 に 紫色の ピン を立てることができました。

[ads]

Map に ピン を複数 追加

[ads]

本記事の最後に 地図上に ピン を複数 追加する方法を紹介します。 今まで作成してきた 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 つの場所に ピン が追加された地図が表示されます。

[ads]

まとめ

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

関連記事

参照情報

Apple Developer Site

Map

How do I add pins and other annota…

[ads]

サンプルコード ( SwiftUI )

[ads]

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)
        }
    }
}
[ads]

複数 ピン を 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)
            }
        )
    }
}
[ads]
Ads