📍
SwiftUI + Mapkitで、Cloud Firestoreを使う
対象者
- MapKitを勉強している
- Cloud Firestoreの経験がある
- 位置情報を保存するアプリを作ってみたい
SwiftUIで、新規プロジェクトを作成する。ShopMapApp
としておきましょうか。
バンドルIDの設定をして、Firebase SDKをSPMを使って追加する。
エントリーポイントのファイルを設定する。
import SwiftUI
import FirebaseCore
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
}
@main
struct ShopMapAppApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
もし、FirebaseCoreがインポートできなかったら、こちらの記事を参考に解決してみてください。
プロジェクトの説明
Cloud Firestoreに、ダミーの位置情報とお店の場所を入れておきましょうか。何件でも入れて良い。最初に表示する場所はお好きな場所を軽度・緯度を設定してください。
渋谷にあるお店の位置情報を入れますか。 GoogleMapを使って、右クリックでお店の緯度・軽度を表示できます。
この情報を Cloud Firestorenに保存しましょう。
お店情報を作成
shop collectionを作成しましょう。このような構造になっております。
/shop
|
-----shop_name: string
|
-----address: string
|
-----location: geopoint
[example]
import SwiftUI
import MapKit
import Firebase
struct ShopAnnotation: Identifiable {
let id = UUID()
var name: String
var coordinate: CLLocationCoordinate2D
var address: String
}
class LocationManager: NSObject, ObservableObject {
// 渋谷駅近辺の座標
@Published var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 35.657567537274865, longitude: 139.70215439869386),
span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
)
@Published var shopAnnotations = [ShopAnnotation]()
@Published var selectedShop: ShopAnnotation?
// ページが呼ばれたタイミングで実行
override init() {
super.init()
fetchShopLocation()
}
// cloud firestore ~ data fetch
func fetchShopLocation() {
let db = Firestore.firestore()
db.collection("shop").getDocuments { [weak self] (querySnapshot, err) in
guard let self = self else { return }
if let err = err {
print("Error getting documents: \(err)")
return
}
var localAnnotations = [ShopAnnotation]()
for document in querySnapshot!.documents {
let data = document.data()
if let shopName = data["shop_name"] as? String,
let location = data["location"] as? GeoPoint,
let address = data["address"] as? String {
let shopAnnotation = ShopAnnotation(
name: shopName,
coordinate: CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude),
address: address
)
localAnnotations.append(shopAnnotation)
}
}
DispatchQueue.main.async {
self.shopAnnotations = localAnnotations
}
}
}
}
struct ContentView: View {
@StateObject private var locationManager = LocationManager()
var body: some View {
// show Map View
Map(coordinateRegion: $locationManager.region, annotationItems: locationManager.shopAnnotations) { shop in
MapAnnotation(coordinate: shop.coordinate) {
Image(systemName: "mappin.circle.fill")
.foregroundColor(.red)
.onTapGesture {
locationManager.selectedShop = shop
}
}
}// pin をタップするとお店の情報を表示
.overlay(
Group {
if let selectedShop = locationManager.selectedShop {
VStack {
Text(selectedShop.name)
.font(.headline)
Text(selectedShop.address)
.font(.subheadline)
}
.padding()
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 5)
.padding()
.transition(.move(edge: .bottom))
.animation(.spring())
}
}, alignment: .bottom
)
}
}
#Preview {
ContentView()
}
感想
ネットに参考になる情報がなかったので、手探りで作りました。難しいですね。どうやってみんな作っているのだろうか...
もっと簡単に地図アプリ作れると良いのだが...
[以前参考にしていた情報]
Discussion