在現(xiàn)代移動(dòng)應(yīng)用中,地圖功能已經(jīng)成為許多應(yīng)用的重要組成部分。SwiftUI 提供了強(qiáng)大的地圖支持,可以輕松地在應(yīng)用中集成地圖,并結(jié)合位置服務(wù)實(shí)現(xiàn)豐富的地理位置功能。本篇博客將介紹如何使用 SwiftUI 顯示地圖,并在地圖中心位置顯示當(dāng)前的地理位置地址。
功能概述
我們將實(shí)現(xiàn)一個(gè)應(yīng)用,該應(yīng)用包含以下功能:
- 顯示全屏地圖。
- 在地圖中心顯示一個(gè)標(biāo)記圖標(biāo)。
- 實(shí)時(shí)獲取并顯示地圖中心位置的地理地址。
準(zhǔn)備工作
首先,我們創(chuàng)建一個(gè)可觀察的 MapService 類,用于管理地圖狀態(tài)和地理編碼功能。
@Observable
class MapService {
var currentPosition = MapCameraPosition.userLocation(followsHeading: true, fallback: MapCameraPosition.region(MKCoordinateRegion.init(center: LocationManager.defaultCoordinate, span: LocationManager.defaultCoordinateSpan)))
var isGeoCoding = false
var address: String? = nil
var currentLocation = LocationManager.defaultCoordinate
func reverGeoCode() {
self.isGeoCoding = true
let center = self.currentLocation
let latitude = center.latitude
let longitude = center.longitude
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: latitude, longitude: longitude)
geoCoder.reverseGeocodeLocation(location) { (placeMarks, error) in
self.isGeoCoding = false
if error != nil {
self.address = error?.localizedDescription
}else{
if let placeMarks, let first = placeMarks.map({$0.description.components(separatedBy: "@").first}).first(where: {$0 != nil}) {
self.address = first
}
}
}
}
}
在 MapService 中,我們使用 @Observable 屬性包裝器使類的屬性的變化能被 SwiftUI 視圖觀察到,并實(shí)現(xiàn)了逆地理編碼的方法 reverseGeoCode。
創(chuàng)建 ContentView 視圖
struct ContentView: View {
@State private var service = MapService()
var body: some View {
ZStack(alignment:.center){
Map(position: $service.currentPosition,interactionModes: .all)
.onMapCameraChange({ result in
print("\(result.region.center)")
service.currentLocation = result.region.center
service.reverGeoCode()
})
Image(systemName: "mappin")
.font(.largeTitle)
.foregroundStyle(.blue)
.offset(y: -16)
bottomView
}
}
@ViewBuilder
var bottomView: some View {
VStack {
Spacer()
VStack {
HStack{
Text("當(dāng)前位置:")
.font(.headline)
.foregroundColor(.black)
Spacer()
}
HStack{
if service.isGeoCoding {
HStack(alignment:.center){
Spacer()
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
Spacer()
}
}else{
Text("\(service.address ?? "null")")
.font(.body)
.foregroundColor(.black)
.padding([.bottom,.top,],10)
}
Spacer(minLength: 10)
}
}
.padding(10)
.background(.bar)
.cornerRadius(10)
.padding()
}
}
}
主要部分分析
1.@State:
使用 @State 來管理 MapService 的實(shí)例,使其在視圖生命周期中被正確管理。
2.Map 視圖:
使用 Map 組件顯示地圖,并綁定 position 屬性到 service.position。
通過 onMapCameraChange 方法監(jiān)聽地圖中心位置的變化,并調(diào)用 reverseGeoCode 更新地理位置。
3.中心標(biāo)記圖標(biāo):
使用 Image(systemName: "mappin") 在地圖中心顯示一個(gè)標(biāo)記圖標(biāo)。
4.底部視圖:
使用 @ViewBuilder 構(gòu)建底部視圖,顯示當(dāng)前地理位置或加載指示器。
逆地理編碼功能
在 MapService 中實(shí)現(xiàn)了逆地理編碼功能。每當(dāng)?shù)貓D中心位置發(fā)生變化時(shí),調(diào)用 reverseGeoCode 方法,將地圖中心的坐標(biāo)轉(zhuǎn)換為人類可讀的地址,并更新 UI
運(yùn)行效果
