在 SwiftUI 框架剛發佈時,開發者需要包裝 MKMapView
類別,來將地圖嵌入到一個 SwiftUI App 中。隨著 Xcode 12 推出,最新版本的 SwiftUI 提供了本機 SwiftUI Map
視圖,讓我們顯示地圖界面。另外,我們還可以使用內建的標註 (annotations) 視圖(像是 MapMarker
)顯示標註。
在這篇教學文章中,我會教大家在 SwiftUI 使用 Map
結構,在地圖上一個特定的位置上創建標註。
在 SwiftUI 中顯示一個 Map 視圖
參考 Map
的文件資料,我們找到這個結構的 init
方法:
init(coordinateRegion: Binding<MKCoordinateRegion>, interactionModes: MapInteractionModes = .all, showsUserLocation: Bool = false, userTrackingMode: Binding<MapUserTrackingMode>? = nil) where Content == _DefaultMapContent
要使用 Map
,我們需要提供 MKCoordinateRegion
的 binding,以追踪要在地圖上顯示的區域。我們可以利用 MKCoordinateRegion
結構,來指定以特定緯度和經度為中心的一個矩形地理區域。
看看以下範例:
MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 40.75773, longitude: -73.985708), span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
範例中的座標是紐約時代廣場的 GPS 座標。 span
的數值是用來定義所需的地圖縮放程度,數值越小,縮放程度就越高。
要將地圖嵌入 SwiftUI
,首先我們要匯入 MapKit
框架:
import MapKit
然後宣告一個狀態變數 (state variable),如此追蹤地圖區域:
@State private var region: MKCoordinateRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 40.75773, longitude: -73.985708), span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
最後,我們使用 Map
結構,並將其與 region
binding 傳遞:
var body: some View {
Map(coordinateRegion: $region)
}
在預覽中,我們會看到一個以紐約時代廣場為中心的地圖界面。
如果想顯示一個全螢幕地圖,可以在 Map
中添加以下的修飾符:
Map(coordinateRegion: $region)
.edgesIgnoringSafeArea(.all)
init
方法提供了幾個可選參數 (optional parameter)。在預設情況下,地圖允許使用者平移 (pan) 和縮放。如果想要禁用地圖的使用者互動,我們可以為 interactModes
參數傳遞一個空的陣列:
Map(coordinateRegion: $region, interactionModes: [])
如果要在地圖上顯示使用者的位置,我們就可以將 showsUserLocation
的值設置為 true
:
Map(coordinateRegion: $region, interactionModes: [], showsUserLocation: true)
我們還可以傳遞 MapUserTrackingMode
的 binding,來追踪使用者的位置:
Map(coordinateRegion: $region, interactionModes: [], showsUserLocation: true, userTrackingMode: .constant(.follow))
在地圖上顯示標註
在 Map
的 API 文檔中,我們會找到另一個初始化器,用於顯示帶有標註的地圖:
init<Items, Annotation>(coordinateRegion: Binding<MKCoordinateRegion>, interactionModes: MapInteractionModes = .all, showsUserLocation: Bool = false, userTrackingMode: Binding<MapUserTrackingMode>? = nil, annotationItems: Items, annotationContent: @escaping (Items.Element) -> Annotation) where Content == _DefaultAnnotatedMapContent<Items>, Items : RandomAccessCollection, Annotation : MapAnnotationProtocol, Items.Element : Identifiable
它與以前的初始化器非常相似,但是它接受一組標註,而每個標註都遵從 Identifiable
協定。
現在,讓我們先為標註物件定義一個結構:
struct AnnotatedItem: Identifiable {
let id = UUID()
var name: String
var coordinate: CLLocationCoordinate2D
}
這個結構用來保存標註的名稱和座標。最重要的是,它遵從 Identifiable
協定。
看看以下例子,我們在 ContentView
定義一個興趣點 (point of interest) 的陣列:
private var pointsOfInterest = [
AnnotatedItem(name: "Times Square", coordinate: .init(latitude: 40.75773, longitude: -73.985708)),
AnnotatedItem(name: "Flatiron Building", coordinate: .init(latitude: 40.741112, longitude: -73.989723)),
AnnotatedItem(name: "Empire State Building", coordinate: .init(latitude: 40.748817, longitude: -73.985428))
]
我們要顯示標註,只需要在實例化地圖時指定陣列即可:
Map(coordinateRegion: $region, annotationItems: pointsOfInterest) { item in
MapMarker(coordinate: item.coordinate, tint: .red)
}
.edgesIgnoringSafeArea(.all)
MapMarker
就是其中一個內建標註視圖,利用氣球形狀標記特定位置。或者,你也可以使用 MapPin
,以大頭針形狀來標記特定位置。
您還可以使用 MapAnnotation
創建客製化的標註。看看以下例子:
MapAnnotation(coordinate: item.coordinate) {
RoundedRectangle(cornerRadius: 5.0)
.stroke(Color.purple, lineWidth: 4.0)
.frame(width: 30, height: 30)
}
你可以看到標註以圓角矩形顯示。設計有無盡的可能,你可以設計自己想要的標註視圖。
下一步
很高興看到 Apple 在 SwiftUI 引入本機 Map
視圖。希望大家學會了如何在 iOS App 中嵌入地圖界面。如果想更深入學習 SwiftUI 框架,可以閱讀我們《精通 SwiftUI》一書。
原文:How to Work with SwiftUI Maps and Annotations