🗾

SwiftUIでMapkitを使ってpinを立てるのと拡大・縮小をやってみる

2024/02/05に公開

読んでほしい人

  • Mapkitを使ってpinを立ててみたい
  • Mapの拡大・縮小をやってみたい

補足情報

公式のコードとか参考にしてるのですが、Mapの書き方が()なのか{}なのかで、出てくるエラーが違いますね。パラメーターを渡せと言われます。今回は動くコードを作れたので、メモ程度の記事です。

記事の内容

このコードでは、IdentifiablePointAnnotationという新しい構造体を作成しています。これはIdentifiableプロトコルに準拠し、MKPointAnnotationを内部に保持します。これにより、MapビューのannotationItemsとして使用できます。

struct IdentifiablePointAnnotation: Identifiable {
    let id = UUID()
    let annotation: MKPointAnnotation
}

マップの拡大と縮小を行うためには、MKCoordinateSpanの値を変更することで実現できます。以下に、拡大と縮小ボタンを追加したコードを示します:

// + ボタンは、地図を拡大します。
                    Button(action: {
                        let span = MKCoordinateSpan(latitudeDelta: region.span.latitudeDelta / 2.0, longitudeDelta: region.span.longitudeDelta / 2.0)
                        region.span = span
                    }) {
                        Text("+")
                    }
                    .padding()
                    .background(Color.black.opacity(0.75))
                    .foregroundColor(.white)
                    .font(.title)
                    .clipShape(Circle())
                    .padding(.trailing)
                    // - ボタンは、地図を縮小します。
                    Button(action: {
                        let span = MKCoordinateSpan(latitudeDelta: region.span.latitudeDelta * 2.0, longitudeDelta: region.span.longitudeDelta * 2.0)
                        region.span = span
                    }) {
                        Text("-")
                    }
                    .padding()
                    .background(Color.black.opacity(0.75))
                    .foregroundColor(.white)
                    .font(.title)
                    .clipShape(Circle())
                    .padding(.trailing)

まず、MKPointAnnotationの配列を作成し、それを@Stateプロパティとして保持します。次に、onTapGestureを使用してタップイベントを取得し、新しいピンを作成して配列に追加します。

こちらが全体のコード

import SwiftUI
import MapKit

// このプロトコルは、IdentifiablePointAnnotation の id プロパティを提供します。
struct IdentifiablePointAnnotation: Identifiable {
    let id = UUID()
    let annotation: MKPointAnnotation
}

struct ContentView: View {
    // region は、地図の表示範囲を定義します。場所は東京です。
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 35.6895, longitude: 139.6917),
        span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
    )
    // locations は、地図上のピンの位置を保持します。
    @State private var locations = [IdentifiablePointAnnotation]()

    var body: some View {
        ZStack {
            // Map は、地図を表示します。
            Map(coordinateRegion: $region, annotationItems: locations) { location in
                MapPin(coordinate: location.annotation.coordinate)
            }
            // onTapGesture は、地図をタップしたときに呼び出されます。
            .onTapGesture {
                let coordinate = region.center
                let newLocation = MKPointAnnotation()
                newLocation.coordinate = coordinate
                self.locations.append(IdentifiablePointAnnotation(annotation: newLocation))
            }

            VStack {
                Spacer()
                HStack {
                    // + ボタンは、地図を拡大します。
                    Button(action: {
                        let span = MKCoordinateSpan(latitudeDelta: region.span.latitudeDelta / 2.0, longitudeDelta: region.span.longitudeDelta / 2.0)
                        region.span = span
                    }) {
                        Text("+")
                    }
                    .padding()
                    .background(Color.black.opacity(0.75))
                    .foregroundColor(.white)
                    .font(.title)
                    .clipShape(Circle())
                    .padding(.trailing)
                    // - ボタンは、地図を縮小します。
                    Button(action: {
                        let span = MKCoordinateSpan(latitudeDelta: region.span.latitudeDelta * 2.0, longitudeDelta: region.span.longitudeDelta * 2.0)
                        region.span = span
                    }) {
                        Text("-")
                    }
                    .padding()
                    .background(Color.black.opacity(0.75))
                    .foregroundColor(.white)
                    .font(.title)
                    .clipShape(Circle())
                    .padding(.trailing)
                }
            }
        }
    }
}

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

このコードは、ユーザーがマップをタップするたびに新しいピンを作成し、それをlocations配列に追加します。そして、マップはその配列のすべてのピンを表示します。

地図を表示:

  • を押して拡大:
  • を押して縮小:

最後に

動画のチュートリアルをやってみたりするのですが、ソースコードが新しいのか古いのかMap書いたあたりからうまくいかないです?
早く仕組みを理解していい感じの地図アプリを作ってみたいです。

Discussion