Integrating MapKit with SwiftUI, 初探
想要在 app 裡加入地圖的功能時,必須使用 MapKit framework 底下的MKMapView
class,其定義如下(詳見文末的官方文件連結):
// An embeddable map interface, similar to the one provided by the Maps application.
class MKMapView : UIView
MKMapView
是一個 UIView,因此無法直接將它應用在 SwiftUI View 裡面,而是得先透過UIViewRepresentable
這個 wrapper 來將它包裝成 SwiftUI 認得的 View(詳見文末的官方文件連結)
。
// A wrapper for a UIKit view that you use to integrate that view into your SwiftUI view hierarchy.
public protocol UIViewRepresentable : View where Self.Body == Never {
...
}
首先,開啟一個新的 app 專案,並在專案底下新增一個 SwiftUI View 檔案,取名為 "MapView.swift"。
- 由於會使用到 MapKit,因此在
import SwiftUI
的下一行必須導入import MapKit
。 - 另外,讓自定的 MapView struct 遵循
UIViewRepresentable
protocol。
// MapView.swift
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
// more code
}
但Xcode 無法編譯以上程式碼,會出現以下錯誤訊息:
" Type 'MapView' does not conform to protocol 'UIViewRepresentable' "。所以,我們必須在 "more code" 的位置補上兩個必要的 function,分別是makeUIView(context:)
和updateUIView(_:context:)
,並在makeUIView()
裡創建一個MKMapView
的實例,然後回傳;至於updateUIView()
的內容,則暫時先留白沒有關係。
//MapView.swift
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
/// Creates the view object and configures its initial state.
/// You must implement this method and use it to create your view
/// object. The system calls this method only once, when it creates
/// your view for the first time. For all subsequent updates, the
/// system calls the ``updateUIView(_:context:)`` method.
func makeUIView(context: Context) -> MKMapView {
// 1.產生一個MKMapView的instance並且回傳
let mapView = MKMapView()
return mapView
}
/// When the state of your app changes, SwiftUI updates the portions
/// of your interface affected by those changes. SwiftUI calls this
/// method for any changes affecting the corresponding UIKit view.
func updateUIView(_ uiView: MKMapView, context: Context) {
// 2.暫時留白無妨
}
}
有一點要注意的是,我們在這兩個 function 的context
參數中直接賦予值 "Context",其實 Context 等同於是UIViewRepresentableContext<Self>
( Self 即是指 MapView )。之所以能簡化為 Context,是因為在 UIViewRepresentable
裡有著這樣的定義(在 Xcode 裡按下 Cmd + Shift + O
,查找 UIViewRepresentable )。
public protocol UIViewRepresentable : View where Self.Body == Never {
...
typealias Context = UIViewRepresentableContext
}
至此,我們已可將自定的 MapView 用於 SwiftUI View,讓我們的 app 出現地圖囉!
// ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
MapView()
.edgesIgnoringSafeArea(.all)
}
}
}
Comments