🛺

SwiftUIでMapKitを使いたい!

2024/01/27に公開

対象者

SwiftUIでMapKitを使って地図を表示する機能を作るのをやってみたい人が対象です。筆者もやってみたい初心者です笑

やること/やらないこと

やること:
SwiftUIの標準のAPIを使う

やらないこと:
MapKitについて深掘りしません。内部のコード見たり調べてみたのですが、公式と書方が違う?
なんかパラメーター渡すとか、プロトコルに準拠してないからとエラーが出ました💦

プロジェクトの説明

まずは、x-codeで新規プロジェクトを作成して、ContentViewに以下のコードを書いてください!

import SwiftUI
import MapKit

struct Location: Identifiable {
    let id = UUID()
    let coordinate: CLLocationCoordinate2D
}

struct ContentView: View {
    let cityHallLocation = Location(coordinate: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194))
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194),
        span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2)
    )

    var body: some View {
        Map(coordinateRegion: $region, annotationItems: [cityHallLocation]) { location in
            MapMarker(coordinate: location.coordinate)
        }
    }
}


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

このように書かないとMapが表示できなかった???
公式やネットのコードが古いのかiOSのバージョンのせいかMap()だけでは使えない?
https://qiita.com/takatein/items/df07b81b4c0545accc43

コードの解説とハマったこと!

MapビューのannotationItemsパラメータは、Identifiableプロトコルに準拠する必要があります。しかし、CLLocationCoordinate2Dはその要件を満たしていません。そのため、Identifiableプロトコルに準拠する新しい型を作成し、その型のインスタンスをannotationItemsに渡す必要があります。

import SwiftUI
import MapKit

struct Location: Identifiable {
    let id = UUID()
    let coordinate: CLLocationCoordinate2D
}

struct ContentView: View {
    let cityHallLocation = Location(coordinate: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194))
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194),
        span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2)
    )

    var body: some View {
        Map(coordinateRegion: $region, annotationItems: [cityHallLocation]) { location in
            MapMarker(coordinate: location.coordinate)
        }
    }
}

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

このコードでは、Locationという新しい型を作成し、それがIdentifiableプロトコルに準拠するようにしています。そして、LocationのインスタンスをannotationItemsに渡しています。

これでもエラが出た!

Location構造体はIdentifiableプロトコルに準拠していますが、それを使用していないようで、cityHallLocationをCLLocationCoordinate2DからLocationに変更する必要がありました。

struct ContentView: View {
    let cityHallLocation = Location(coordinate: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194))
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194),
        span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2)
    )

    var body: some View {
        Map(coordinateRegion: $region, annotationItems: [cityHallLocation]) { location in
            MapMarker(coordinate: location.coordinate)
        }
    }
}

この修正により、annotationItemsパラメータにIdentifiableプロトコルに準拠したLocation型のオブジェクトを渡すことができます。

Previewで表示できた💦

感想

MapKitの公式を見てみたが、私の環境ではなぜか使えない???
チュートリアルの動画も見てみたが、Mapのところの括弧の書方が違う気がした???
x-codeのバージョンは、14.3.1を使用しております。

https://developer.apple.com/documentation/mapkit/map

追加情報

東京都渋谷の情報を表示するには、このように書けばできます。
Mapの中に、以下のようなパラメーターを渡す必要がある。

import SwiftUI
import MapKit

struct ContentView: View {
    // 東京渋谷の座標
    let shibuyaCoordinate = CLLocationCoordinate2D(latitude: 35.658035, longitude: 139.701636)
    
    var body: some View {
        Map(coordinateRegion: .constant(MKCoordinateRegion(
            center: shibuyaCoordinate,
            span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
        )))
        .edgesIgnoringSafeArea(.all)
    }
}

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

Discussion