LoginSignup
2
1

More than 1 year has passed since last update.

【WidgetKit】ウィジェットの編集項目をカスタムする方法

Last updated at Posted at 2022-12-04

フリューAdvent Calendar 2022の4日目を担当します、f_nksksです。
今回はSwiftUIのWidgetKitについて、ウィジェットの編集画面をカスタムする方法について記事にしていこうと思います。
よろしくお願いします。

やりたいこと

  • ウィジェットを長押し→ウィジェットの編集ができる
  • ウィジェット編集画面で、任意の項目を選択できる
  • 項目選択した後、その項目に属する追加の設定項目が出現する
    画面収録_2022-12-04.gif

※設定内容のウィジェット側への反映や、アプリ側で設定したデータの連携などは、また別途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についても同様にパラメータを追加し、RelationshipValueを"type2"にすることで、同様の状態となります。

注意点なのですが、

widgetType(親) -> childType1_1(子) -> ×(孫)

といったように、childType1_1に対し、更に子パラメータを追加することはできないようです。
Relationshipは1階層しか出来ない前提でウィジェット編集画面の構成を考える必要があります。

最後に

無事、ウィジェットの編集ができるようになりました。
設定できるだけだと汎用性がないので、アプリ側で設定・保存した値を読み込んだり、ウィジェットに反映する必要があります。
今後そちらの方法についても記事にしていきたいと思います。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1