【SwiftUI】UIViewRepresentableの使い方!Coordinatorクラスとは?

この記事からわかること
- SwiftUIでUIKitを使えるようにするには?
- UIViewRepresentableプロトコルの使い方
- makeUIViewメソッドとupdateUIViewメソッドの違い
- UIKitのイベントをSwiftUIに伝える
- UILabelとUIButtonをSwiftUIで扱う方法
- Coordinator(コーディネータ)クラスとは?
index
[open]
\ アプリをリリースしました /
iOSアプリを開発するためのプログラミング言語である「Swift」の代表的なフレームワークが「UIKit」と「SwiftUI」です。
今回は「SwiftUI」から「UIKit」を使えるようにできるUIViewRepresentableプロトコルの使い方と概要についてまとめていきたいと思います。
おすすめ記事:Swiftとは?Swift UIとの違いと特徴やメリット
UIViewRepresentableプロトコルとは?
「UIViewRepresentableプロトコル」とはUIKitのビューや機能をSwiftUIでも使えるようにするラッパーの役割も持つプロトコルです。そもそもUIKitのビューを管理するUIViewController
とSwiftUIのView
はベースが異なるので、両者をそのままつなぎ合わせることはできません。
また「UIKit」は古くから使用されてきたフレームワークなので豊富な機能やビューが提供されています。一方比較的新しいフレームワークである「SwiftUI」はまだまだ実装できる機能には制限がありできることは限られてきます。
「互換性のないビュー」と「機能の豊富さの差異」を解決するために両フレームワーク間の機能の橋渡しするためのラッパーが用意されています。
両フレームワーク間の機能の橋渡しするためのラッパー
- UIKitでSwiftUIを使用:UIHostingControllerクラス
- SwiftUIでUIKitを使用:UIViewRepresentableプロトコル
UIViewRepresentableプロトコルの使い方
SwiftUIでUIKitを使用するためのUIViewRepresentable
プロトコルは構造体に準拠させて使用します。定義を見てみると以下の2つのメソッドの実装が必須になっています。
定義
ちなみにUIViewRepresentable
プロトコルをクラスに準拠させる場合はfinal class
にしないと以下のようなエラーを吐きます。
とはいえUIKitは主にクラスで定義されているの対し、SwiftUiは主に構造体で定義されているので準拠させていくのは構造体になります。
makeUIViewメソッド
makeUIView
メソッドは表示するViewの初期状態のインスタンスを生成するメソッドです。SwiftUIの中で使用したいUIKitのViewを戻り値として返却します。
このメソッドは最初の一回しか呼び出されず、ビューを更新する場合はupdateUIView
メソッドに処理を定義します。
引数context
にはUIKitビューの作成と更新に使用するシステムの状態に関するコンテキスト(文脈)情報が渡されます。つまりビューを構築するために必要な情報のことです。
戻り値には表示させたいUIKitのViewの型(UIViewType)を指定します。ここで戻す型が実際にSwiftUIで表示させたいUIKitの型になります。最初のコード補完では上記のように-> Self.UIViewType
となります。この部分を直接指定の型に書き換えるもしくはUIViewType
を指定の型のタイプエイリアスとして宣言しておく必要があります。
直接指定するパターン
タイプエイリアスとして宣言するパターン
updateUIViewメソッド
updateUIView
メソッドは表示するビューの状態が更新されるたびに呼び出され更新を反映させるためのメソッドです。
例えばUIViewRepresentable
プロトコルに準拠させた構造体のプロパティなどが変更された時などに呼び出されます。
UIViewRepresentable〜まとめ〜
- UIKitをSwiftUIで使える役割を持たせるためのプロトコル
- 構造体に準拠させて使用
- makeUIViewとupdateUIViewの2つのメソッドの実装が必須
- makeUIView:初期表示用のメソッド
- updateUIView:更新用のメソッド
使用方法1:SwiftUIの変更をUIKitに伝える
実際にUILabel(UIKitのビュー)をSwiftUIで表示させてみたいと思います。ラベルを表示させるだけではなくSwiftUIのButton
構造体で定義したボタンをクリック時にラベルのテキストを変更させます。
- UIViewRepresentableに準拠させた構造体を作成
- isClickプロパティをバインディングで定義
- makeUIViewメソッド内でUILabelを構築しreturn
- updateUIViewメソッドではバインディングしたプロパティの値の変化をキャッチできるので値に応じて処理を分岐
- LabelView()としてインスタンス化してビューを表示
これでボタン(SwiftUI)をクリックした時にUILabel(UIKit)のテキストを変更する機能が完了しました。
使用方法2:UIKitのイベントをSwiftUIに伝える
ではUIKitのUIButton
をクリックされた時にUILabel
を変更する方法を考えてみます。まずはUIButton
をSwiftUIで使えるように先ほどと同じ手順で定義していきます。今回は特にボタンは変更しないのでupdateUIView
は空にしておきます
これでUIButton
をSwiftUIで表示できるようになりましたが、クリック時(UIKit側のイベント)の処理はまだ記述できていません。
UIKit側のイベントを取得するにはCoordinator(コーディネータ)クラスを構造体の中に定義して実装していきます。
Coordinator(コーディネータ)クラス
Coordinator(コーディネータ)クラスとはUIKitでのイベントをSwiftUIで管理するために作成するクラスのことです。このクラスはデフォルトで存在するわけではなく、自分で実装します。そのためクラス名に決まりはないですが構造体の中で定義するため名前の衝突を気にする必要がないので分かりやすくCoordinator
としておきます。
Coordinator
クラスの中には「観測対象プロパティの宣言」と「イベント発生時の処理」を実装していきます。
- Coordinatorクラスを構造体の中に作成
- プロパティに定義したビューをセット
- イニシャライザで引数を自身にセット
- イベント発生時の処理(clickButton)を記述する
- インスタンス化用の専用メソッド(makeCoordinator)を構造体内に定義
- makeUIViewメソッドにアクション部分を定義
まずはクラスを定義します。@objc
はSwift前身のObjective-Cのコードとして扱うためのコードです。これは後述する#selector
と関係しています。その中にアクションで行う処理を記述しておきます。
続いてCoordinator
クラスをインスタンス化するためのmakeCoordinator
メソッドを準備します。これはUIViewRepresentable
にあらかじめ用意されているメソッドでmakeUIView
メソッドが呼び出される前に一度だけ呼びだされインスタンス化されます。
インスタンス化されるとmakeUIView
メソッドの引数context
の中から参照できるようになります。UIButton
のアクション部分を実装するaddTarget
メソッドにCoordinator
を渡していきます。#selector
を使ってメソッドを指定します。
私がSwift UI学習に使用した参考書
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。