🙆‍♀️

SwiftUI MapKit 基礎

2024/07/10に公開

MapKitを追加する方法

以下のようなコードを書くとマップが登場します

import SwiftUI
import MapKit

struct ContentView: View {
    var body: some View {
        Map()
    }
}

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

アノテーションをつける

まずは自分の建てたいピンの位置の緯度と軽度の座標を調べる
*Swiftではdegree形式がデフォルト

CLLocationCordinate2Dを使い座標を指定する

import SwiftUI
import MapKit

extension CLLocationCoordinate2D {
    static let kamikitazawa_sta = CLLocationCoordinate2D(latitude: 35.6689, longitude: 139.6234)
}

struct ContentView: View {
    var body: some View {
        Map {
 Annotation("Kamikitazawa-Station",
                       coordinate: .kamikitazawa_sta, anchor: .bottom) {
                VStack {
                    Text("Kamikitazawa Sta")
                    Image(systemName: "flag.2.crossed")
                }
                .foregroundColor(.blue)
                .padding()
                .background(in: .capsule)
            }
        }
    }
}

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

地図のスタイルの変更

3Dにするためには.mapStyle(.standard)から .mapStyle(.standard(elevation: .realistic))にする

import SwiftUI
import MapKit

struct ContentView: View {
    var body: some View {
        Map()
        .mapStyle(.standard(elevation: .realistic))
    }
}

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

現実的にするには.mapStyle(.standard)から.mapStyle(.imagery)に変える

import SwiftUI
import MapKit

struct ContentView: View {
    var body: some View {
        Map()
        .mapStyle(.imagery(elevation: .realistic))
    }
}

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

現在位置を表示する

プロジェクトナビゲーターで、プロジェクトの「Info.plist」ファイルを探し、選択します
「Information Property List」セクションで、右上の「+」ボタンをクリックし、新しいキーを追加します
表示されるウィンドウで「Privacy - Location Always and When In Use Usage Description」キーを選択します
キーの横にある値の欄に、ユーザに向けた位置情報使用の理由を説明する文字列を入力します (例: "現在地を表示させるために必要です")

参考記事

import SwiftUI
import MapKit
import CoreLocation
import Combine

struct ContentView: View {
    @StateObject private var locationManager = LocationManager()

    var body: some View {
        Map(coordinateRegion: $locationManager.region, showsUserLocation: true, annotationItems: locationManager.annotations) { annotation in
            MapMarker(coordinate: annotation.coordinate)
        }
        .edgesIgnoringSafeArea(.all) 
        .onAppear {
            locationManager.requestLocation()
        }
    }
}

class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    private let manager = CLLocationManager()

    @Published private(set) var annotations: [LocationAnnotation] = []
    @Published var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 35.6895, longitude: 139.6917), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))

    override init() {
        super.init()
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyBest
    }

    func requestLocation() {
        manager.requestWhenInUseAuthorization()
    }
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }

        let annotation = LocationAnnotation(coordinate: location.coordinate)
        annotations = [annotation]

        let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
        let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) 
        region = MKCoordinateRegion(center: center, span: span)

        DispatchQueue.main.async {
            self.objectWillChange.send()
        }
    }
}

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

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

MapKitのcontrols

import SwiftUI
import MapKit

struct ContentView: View {
    
    @Namespace var mapScope
    
    var body: some View {
        Map (scope: mapScope)
            .overlay(alignment: .bottomTrailing) {
                VStack {
                    MapUserLocationButton(scope: mapScope)
                    MapPitchButton(scope: mapScope)
                    MapCompass(scope: mapScope)
                        .mapControlVisibility(.visible)
                }
                .padding(.trailing, 10)
                .buttonBorderShape(.circle)
            }
            .mapScope(mapScope)
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
}

参考資料

https://zenn.dev/jboy_blog/articles/b969aa12399344
https://qiita.com/takatein/items/df07b81b4c0545accc43
https://www.youtube.com/watch?v=efjxmrAIobU&ab_channel=AppleDeveloper
https://developer.apple.com/documentation/mapkit/mapuserlocationbutton/4235127-mapcontrols

Discussion