フリューAdvent Calendar 2022の4日目を担当します、f_nksksです。
今回はSwiftUIのWidgetKitについて、ウィジェットの編集画面をカスタムする方法について記事にしていこうと思います。
よろしくお願いします。
やりたいこと
※設定内容のウィジェット側への反映や、アプリ側で設定したデータの連携などは、また別途Qiitaの記事に書く予定なので、一旦ウィジェット編集画面が動くようになっていればOKとします。
前提
- プロジェクト作成済
- Widget Extentionをターゲットに追加済みで、ウィジェットが表示できる状態になっている
開発環境
- XCode 13.3.1
- Target: iOS 14.0
手順
ウィジェットの編集画面を表示
ウィジェット編集画面を表示するために、まずはIntentHandlerを追加します。
新規ターゲットとしてIntents Extension
を作成します。
ターゲット直下のInfo.plistを開いて、IntentSupported
のItemとしてConfigurationIntent
を追加しておきます。
続いて、Widget Extentionターゲットにある、Configrationファイル(ターゲット名.intentdefinition)の中身を変更します。
ひとまずはParametersにある+
ボタンから1つパラメータを追加します。
色々設定できそうですが、ひとまずTypeを仮でInteger
にしておきます。パラメータ名はwidgetTypeとしておきました。
ビルドしてアプリのウィジェットを長押しすると、クイックアクションメニューからウィジェットの編集画面が開けるようになりました。
数値が入力できるようになっています。
任意の項目を設定できるようにする
これだけだと数値入力しか出来ないので、「タイプ1」「タイプ2」の文字列のどちらかを選択できるように修正していきます。
まずはWidget ExtentionターゲットのConfigrationファイルを編集します。
Target MembershipにIntents Extensionターゲットを追加しておきます。
先ほど作成したwidgetTypeパラメータについて、TypeからAdd Type
を選択します。
するとTYPESに項目が追加されるので、名前をWidgetTypeに変更しておきます。(後々扱う型名になります)
また、Dynamic Options
の2つのチェックボックスにもチェックを入れておく必要があります。ここをtrueにしておかないと、動的に項目一覧を適用する事ができません。
続いて、Intents Extensionターゲット内の、IntentHandler.swift
ファイルを開き、Target MembershipにWidget Extensionターゲットを追加します。
コードにはIntentHandlerクラスが既に記述されているので、ConfigurationIntentHandling
プロトコルを追加します。
class IntentHandler: INExtension , ConfigurationIntentHandling {
override func handler(for intent: INIntent) -> Any {
return self
}
}
エラーメッセージからprotocol stubを実装してください
と言われるので、fixするとWidgetType一覧を設定するためのメソッドを自動生成してくれます。
この中身を書き換えていきましょう。
WidgetTypeにidentifier
(固有のID)とdisplay
(選択時に表示される文字列)をそれぞれ定義し、一覧にしてcompletionの第一引数に渡してやります。
今回はタイプ1/タイプ2が選択できればいいので、以下のように記述しました。
func provideWidgetTypeOptionsCollection(for intent: ConfigurationIntent, searchTerm: String?, with completion: @escaping (INObjectCollection<WidgetType>?, Error?) -> Void) {
let widgetTypeIdentifiers: [WidgetType] = [
WidgetType(identifier: "type1", display: "タイプ1"),
WidgetType(identifier: "type2", display: "タイプ2"),
]
let allWidgetTypeIdentifiers = INObjectCollection(items: widgetTypeIdentifiers)
completion(allWidgetTypeIdentifiers, nil)
}
この状態でウィジェット編集画面を開くと、先ほど設定したタイプ1/タイプ2をそれぞれ選択できるようになっているかと思います。
子パラメータを追加する
ウィジェットの編集画面でタイプ1を選択した時に、追加パラメータとして「タイプ1-1」を、
タイプ2を選択した時に「タイプ2-1」の項目を表示するように設定していきます。
widgetTypeを追加した時と同様に、ConfigrationのパラメータにchildType1_1を追加します。(一旦表示できればいいので、Typeは仮)
Relationship:Parent Parameter
に対し、今回親パラメータとしたいwidgetType
を選択します。
さらにShow If Parent
が設定できるようになったので、ここをidentifier contains
に変え、先ほどIntentHandlerの実装で設定したWidgetTypeのidentifier(今回は"type1")を記入します。
これで、「WidgetTypeでタイプ1が選択されたときに、ウィジェット編集の選択項目にタイプ1-1が追加される」状態になりました。
タイプ2についても同様にパラメータを追加し、Relationship
のValue
を"type2"にすることで、同様の状態となります。
注意点なのですが、
widgetType(親) -> childType1_1(子) -> ×(孫)
といったように、childType1_1に対し、更に子パラメータを追加することはできないようです。
Relationshipは1階層しか出来ない前提でウィジェット編集画面の構成を考える必要があります。
最後に
無事、ウィジェットの編集ができるようになりました。
設定できるだけだと汎用性がないので、アプリ側で設定・保存した値を読み込んだり、ウィジェットに反映する必要があります。
今後そちらの方法についても記事にしていきたいと思います。