SwiftUI Map 視圖 讓我們更簡單顯示地圖界面和客製化標註


在 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)
}

在預覽中,我們會看到一個以紐約時代廣場為中心的地圖界面。

swiftui-map

如果想顯示一個全螢幕地圖,可以在 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,以大頭針形狀來標記特定位置。

swiftui-map-annotations

您還可以使用 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》一書。

譯者簡介:Kelly Chan-AppCoda 編輯小姐。
原文How to Work with SwiftUI Maps and Annotations


軟件工程師,AppCoda 創辦人。著有《iOS 13 App 程式設計實力超進化實戰攻略》、《iOS 13 App 程式設計實力超進化實戰攻略》以及《精通 SwiftUI》。曾任職於HSBC, FedEx等公司,專責軟體開發、系統設計。2012年創立AppCoda技術部落格,定期發表iOS程式教學文章。現時專注發展AppCoda,致力於iOS程式教學,產品設計及開發。

blog comments powered by Disqus
Shares
Share This