この投稿は何?
SwiftUIフレークワークは宣言的にコードを記述することで、すばやくアプリケーションを開発できます。ただ、これまでのUIKitやAppKitで利用してきたUIコンポーネントのすべてがSwiftUIフレームワークに含まれてはいません。
この投稿では、SwiftUIフレームワークの中でMapKitビューを利用する 方法を例に、UIKitビューをSwiftUIで扱う手順を解説します。
環境
- macOS10.15 beta8
- Xcode11 GM Seed2
この投稿で構築するビューの画面
実装手順
Content.swift に直接、地図ビューを構築することもできます。
ただ、_SwiftUIフレームワーク_による開発は 小さいビューを組み合わせる ことをコンセプトとしています。
地図を表示するだけの_カスタムSwiftUIビュー_を作ってから、_Content.swift_で利用することにします。
SUMapView.swift
カスタムSwiftUIビューを記述するファイルです。
MapViewをSwiftUIビューとして利用するので、SUMapView
という名前にしました。
全体のソースコード
プレビュープロバイダは一切、コードを編集していないのでプレビュー定義の部分は省略しています。
import SwiftUI
import MapKit
struct SUMapView: UIViewRepresentable {
typealias UIViewType = MKMapView
func makeUIView(context: UIViewRepresentableContext<SUMapView>) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<SUMapView>) {
let coordinate = CLLocationCoordinate2D(latitude: 37.3351, longitude: -122.0088)
let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
let region = MKCoordinateRegion(center: coordinate, span: span)
uiView.setRegion(region, animated: true)
}
}
SUMapViewの画面
1. ファイル作成
新しいファイルを作成します。
- メニューバーから「File > New > File...」を選択する。
- iOSのSwiftUI Viewを選択して、Nextをクリックする。
- ファイル名をSUMapView.swiftをして、Createをクリックする。
2. MapKitフレームワーク
import
キーワードで、このファイルにMapKitを導入します。
import SwiftUI
import MapKit
3. UIViewRepresentableプロトコル
SUMapView
構造体にUIRepresentable
プロトコルを採用します。
strict SUMapView: UIViewRepresentable {
...
}
この時点で、UIViewRepresentable
プロトコルに準拠するための要件を満たしていないので、エラーになります。また、SwiftUIビューとしてUIKit系のビューを描画するには、以下に挙げる2点のメソッドを実装する必要があります。
-
makeUIView(context:) -> Self.UIViewType
メソッドを実装する -
updateUIView(_:context:)
メソッドを実装する
4. makeUIView(context:) メソッド
makeUIView(context:)
メソッドは「SUMapView
構造体がどんなビューか?」を決定します。このメソッドが返すSelf.UIViewType
型が、カスタムSwiftUIビューとして扱いたいUIKit
ビューの型になります。
ここではMKMapView
型のことです。
makeUIView(context:)
メソッドを記述しようとすると、Xcodeの補完機能が作動します。
該当するメソッドを選択すると、以下のように記述が補完されます。
func makeUIView(context: UIViewRepresentableContext<SUMapView>) -> SUMapView.UIViewType {
// code...
}
// code...
の部分に、以下のように記述して MKMapView
型のビューを返すようにします。
MKMapView(frame: .zero) // return は省略
メソッドがUIViewType
と一致する型を返していないので、下記のエラーが表示されます。
Reference to invalid associated type 'UIViewType' of type 'SUMapView'
5. UIViewType
UIViewType
型は未定義なので、任意の型として定義します。
typealias UIViewType = MKMapView
これで、makeUIView(context:)
メソッドが宣言する返り値型が MKMapKit(frame: .zero)
と一致するようになったので、エラーが解消されます。
ちなみに...
先に UIViewType
のタイプエイリアスを定義してから、makeUIView(context:)
メソッドを実装すると以下のように補完されます。
func makeUIView(context: UIViewRepresentableContext<SUMapView>) -> MKMapView {
// code....
}
返り値の型に注目してください。
タイプエイリアスの宣言を探す必要がなく、ビューの型が理解できます。
6. updateUIView(_:context:) メソッド
このメソッドでは、「ビューが描画されるときの内容」を定義します。ここでは、Appleデベロッパーの聖地 Apple Park の地図を表示することにします。
実装すると、エラーがすべて解消されます。
ContentView.swift
プロジェクトに最初から含まれる既定ファイルです。
このビューに、作成したカスタムSwiftUIビュー SUMapView
を組み込むカタチにします。
全体のソースコード
プレビューの定義は省略しました。
デフォルトのTextビューをSUMapView
に置き換えます。
import SwiftUI
struct ContentView: View {
var body: some View {
SUMapView()
.edgesIgnoringSafeArea(.all)
.statusBar(hidden: true)
}
}
モディファイアも使えるので、、MapKitビューがSwiftUIビューっぽく利用できていることがわかります。