ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
優れたウィジェットの原則
ウィジェットの関連性とカスタマイズ性を維持することで、優れたウィジェットの基盤要素について検証します。タイムラインエントリとTimelineReloadPoliciesを使用してウィジェットを最新の状態に保つ方法を確認します。異なる表示環境や物理的位置にウィジェットを適応させる方法についても紹介します。最後に、ユーザの希望どおりにパーソナライズできるカスタマイズ可能なウィジェットを作成する方法を解説します。
リソース
関連ビデオ
WWDC22
WWDC21
WWDC20
-
ダウンロード
♪ ♪ こんにちは システムエクスペリエンス チームのエンジニアの ブレッド・ケートーです 今日のテーマは 優れたウィジェットの原則 最高のウィジェットを 作るのに役立つ ホットな話題を ご紹介します 私たちはiOS 14に WidgetKitを導入しました WidgetKitにより 美しく ダイナミックな マルチプラットフォームの ウィジェットを作成でき iOSやiPadOS macOSの ホーム画面上に直接配置できます
スタートする前に WWDC 2020を見逃した方には 素晴らしい講演があります ”WidgetKitについて”は WidgetKitフレームワークと そのコアコンセプトを紹介します ”Widget Code-Along”は 複雑さを増していく ウィジェット構築について 基礎から応用まで 3部構成で紹介します ”ウィジェットにおける SwiftUIビューの構築”では SwiftUIを最大限に活用して ウィジェットに適応可能な ビューの構築方法を 説明しています 最後に”優れたウィジェット をデザインする”ではデザインの考察を ヒューマン・インターフェース・ グループが解説します
今日は優れたウィジェットの ための2つのトピック 関連性の維持と カスタマイズについて 話します それではまず 関連性について 関連性には 3つのタイプがあります ウィジットが 最新の状態であるかや 環境に適応しているか 確認するために 私たちが徹底的に 議論すべきことです では 時間と プレゼンテーション そして場所という 関連性についてお話します WidgetKitの中心となるのは タイムラインです これは 一日中 関連性を保つための Widgetsの核となる 仕組みです タイムラインは複数の エントリで構成されています この例では3つのエントリが 表示されています 午前9時 午前9時30分 そして午前10時 システムがウィジェットに タイムラインを要求するとき 結果のタイムラインは アーカイブされ エントリが指定した時間に 表示されます これにより ユーザーが ユーザーインターフェースを 必要とするときに すぐに 表示できるようにします いくつか例を 見てみましょう 最も単純なものから その中にどのような コンテンツがあるのか
ここでは最もシンプルな タイムラインの例として シングルエントリである スクリーンタイムです さて スクリーンタイムは 未来のデータを 予測することはできません 厳密にユーザーのデバイスが どう使用されたかという 統計的な履歴に もとづいています タイムラインにおける複数の エントリの利用はできません そのため 単一の エントリを使用します これが 最もシンプルな タイムラインです とはいえ すべてのウィジェットが シングルエントリである 必要はありません 考えてみてください なぜタイムラインに 複数のエントリを 提供しないのか もし 将来性のあるコンテンツや 重要な日付や期限があるとき またはコンテンツの将来を 予測できる場合は ウィジェットは タイムラインで複数の エントリを利用すべきです 別の例として天気の場合です ご覧の通り 天気のタイムラインでは 1日の終わりに向けて 複数のエントリがあります 現時点では最初のエントリが 最も正確です なぜなら 現時点での天気を 示しているからです それ以降のエントリは すべて 予測データを 表しています この追加の予測データが 非常に便利です ウィジェットのリロードは 指定した正確な時間に リロードされると 限りません そして リロードが その目標の時間に 発生しなかった場合 予測されたコンテンツが あることにより ユーザーの利便性が 向上します
写真の例をご紹介します 写真のタイムラインには 個人的または 関連する写真が 1日のうちの 特定の時間に表示されます 私にとっては これらは 本当に素晴らしい思い出です そして 1日に数回しか リロードされませんが 複数の タイムラインエントリから 新しい新鮮なコンテンツを 提示することで 常に活気に満ちた印象を 与えています ご覧のように 天気のような 予測可能なデータがなくても この写真の例のように ユーザーに関連する コンテンツを取り組み タイムラインの 複数のエントリを活用して 驚きと喜びを 与えることができます
さて ウィジェットの中には 他よりも多く見られるものもあるので 更新の公平性を 与えることにしました これを”アップデート バジェット”と呼んでいます 1日の中で蓄積されていき ユーザーの視聴習慣に 大きく影響されます よく見られるウィジットは 1日に 約40から70回 バックグランドで 更新できます これは ユーザーが 起きている通常の時間帯に 均等に配置した場合 約15分から30分ごとに 更新されることになります しかし 当然のことながら 全てのリロードが等間隔で 行われる必要はありません 私たちの目的とするのは さまざまな要求に応じた 多様な更新サイクルのサポートです
例えばスポーツウィジェット があるとします 好きなチームの試合開始前は ほとんど動いていない状態ですが 試合前 試合中 そして試合後に 多くのスコアの更新情報を 受け取ることができます
WidgetKitはスマートで ユーザが寝ているときなど 長時間デバイスを 使用していないときは アップデートを 保留することがあります あるいは 特定のウィジェットの バジェットが利用可能になるまで 更新が 保留されることがあります とはいえ リロードは 毎秒といった オペレーションではありません ウィジェットは ホーム画面上で ライブ感を 演出するものではありません あなたのウィジェットを 1日中更新させる方法は 数多くあります これから それぞれの 機能を簡単に説明し その内容と仕組みを 解説していきます 先ほどご紹介した バジェットとの関係についても どのように機能するのか ご説明します 1つ目は TimelineReloadPolicyです これはWidgetKitのAPIです これは 自動的に行われる リロードの中核となる 仕組みです タイムラインを提供する場合 リロードポリシーも 一緒に提供します このリロードポリシーは バックグランドで自動的に ウィジェットに更新したい タイミングをシステムに通知します これらの自動更新は あなたのウィジェットの 現在の利用可能なバジェットが 消費されます
次は WidgetCenterの リロードAPIです ウィジェットの既存データが 無効になる事態が起きた時 あなたのウィジェットを リフレッシュするAPIです 通常 このAPIを使った リクエストは 利用可能な バジェットを消費します つまり アップデートは バジェットが利用可能に なるまで 行われません しかしこのようなリロードを すぐに またバジェットをかけずに 行うことができる例外的な 状況があります あなたのコンテナAppが フォアグラウンドである時や ナビゲーションや オーディオの再生など Appがユーザーセッション に参加している時です
このAPIは TimelineReloadPolicy API による自動バックグランド の更新を補充するものです 著しく位置が変わった時にも ウィジェットを更新できます ウィジェットが位置情報を 使用しており さらにシステムが 著しい 位置情報の変更を検知すると バジェットに影響を与えずに アップデートすることができます リフレッシュは ユーザーが 次にウィジェット表示した時 更新されるので 位置情報が 適切に解決されます ただ これは位置情報の 変更が発生した時や 次にユーザーが ウィジェットを見た時に すぐに起こることを 保証するものではありません 位置情報については 後でも少し詳しくお話します システムは 表示環境が変化した場合も ウィジェットを更新します 例えば ユーザーが ダイナミックテキストや 太字などの アクセシビリティの設定を 変更した場合や 言語や地域 iCloudまたはApp Storeの アカウントの変更 大幅な時間の変更 などが考えられます 最後に バジェットの関係で ユーザーが滅多に見られない ウィジットをもっている場合 開発者がのぞむほどに 更新されないかもしれません あなたのタイムラインに どのような日付のものがあるのか そして好みの更新時間を システムは把握しています さらに ユーザーの 一般的な閲覧履歴もです システムは ユーザーが閲覧したときに データが古くなっている 可能性がある場合 バジェットのないリロードを 許可することがあります もちろん これら全ての システム主導の更新は 常にバジェットに影響を与えません 先程の話のように それぞれのタイムラインは リロードポリシーとペアで バックグランドで いつ自動的に更新されるかを 示します WidgetKitでは”atEnd” ”afterDate””never” の3つの選択肢があります この3つの リロードポリシーのうち あなたのウィジェットに 適切なリロードポリシーは? さあ それぞれについて 例を上げて説明しましょう そして それぞれについて 注意すべき点を 説明しましょう
最初はatEndリロード ポリシーの紹介です このポリシーは タイムラインが終了した時に あなたのウィジェットが 更新されます 当然 最後のエントリが 関連するようになった時です 今回の場合は 午前10時30分です 注意してください この時間は 単にウィジェットが 更新できるようになった 時間です 更新を保証するものでは ありません さらに atEndを使用する場合 Screen Timeの例のように タイムラインが一つしかない ウィジェットでは システムが ウィジェットに対する適切な 時間を選択してくれます あなたのウィジットが現在の タイムラインの寿命をこえる コンテンツがすでにあるなら AtEndをお勧めします ウィンドウのように コンテンツを見て 考えるのが良いでしょう 例を見てみましょう ここにあるのはカレンダー ウィジェットの現在の タイムラインが6月7日のものです 4つのエントリーがあります 過去と未来のコンテンツも 含めて ウインドウを見せるために 6月8日のタイムラインに 変更してみましょう ウィンドウを内容にあわせて 表示することは どういうことか 確認ができます
再び6月9日の タイムラインを見ましょう 私たちはただ ユーザーから提供された データの見方を 変えるだけです このようなコンテンツこそ atEndポリシーの 真価が発揮される 場面だと思います
atEndポリシーを利用した ウィジェットの例としては リマインダー カレンダー 写真 Tipsなどがあります 繰り返しですが これらは ウィンドウとして見れる 未来に無限のコンテンツ を持つウィジェットです シングルエントリの タイムラインは システムがリロード時間を 選択するためあまり適していません あなたが望んでいるものでは ないでしょう 時間が経つと関連性や 正確性を失うような 予測コンテンツがある場合も お勧めできません 私たちはシンプルに あなたのコンテンツが 最も関連性が高くなるように したいのです もし私たちがタイムラインの 最後まで待っていたら 最も関連性の低いものが 更新の対象に なってしまいます それでは最高のユーザー 体験にならないのです これがatEndですね 次は afterDateについて リロードポリシーは 指定された日付の後に ウィジェットを リロード対象にします afterDateを使用すると 対象となる時間を 完全に コントロール することができます この例では タイムラインは 午前9時から午前11時 頃までとします ウィジェットの リロードポリシーの日付は 午前9時30分を選択 これは 午前9時45分から 予測データの精度が 低下し始めるからです これにより 午前9時30分に すぐにリロードされなくても ウィジェットには 予測データが 表示されます
afterDateは 1日を通して 予測できない あるいは
正確性や関連性が 定期的に変化する データに最適です
afterDateを使用する ウィジェットの例としては 株価 天気 ニュース メールなどがあります これらは予測できないまたは 予測せぬ形で変化する 可能性のあるコンテンツを もつウィジェットです さてafterDateでは いくつかの潜在的な問題に 注意しなければなりません 注意すべき点は即座に リロードを行うこと 1分程度先の日付を 指定することは有効ですが 通常は 非常に限られた 時間の中でのみ有効です このレベルの解像度で 更新の回数が多すぎると 後でリロード できなくなります
また 多くのデバイスで ウィジェットの更新日を 合わせる場合にも 注意が必要です 例えば 東海岸では 午前9時30分に 米国株式市場が開かれ その日の最初のデータを サーバーから取得します 覚えておいてください あなたのウィジェットは 数千、数百万のデバイスに 表示される可能性があり それぞれのデバイスで 複数回表示される 可能性もあります このように時間を合わせてデータを 取り出す必要がある場合は キャッシングサーバに ヒットするだけでなく これらの日付に ある程度のランダムジッタを 追加することを 検討する必要があります これらは 想定外のコストや 不必要なコストが 発生しないようにするために 特に重要です 最後に 私のお気に入りの リロードポリシー neverについて お話しましょう neverリロードポリシーは 自動的なリロードがないので 最もシンプルな ポリシーです ウィジェットのコンテンツが コンテナAppが フォアグラウンドになることや プッシュ通知のような 個別のイベントでのみ そのコンテンツが変化する場合 neverはウィジェットに 最適な選択肢です neverポリシーを利用すると WidgetCenterの リロードAPI または その他の付属拡張機能を 使用し ウィジェットを 最新の状態に保ちます これにより リロードが発生を最小限にし バジェットやユーザーの バッテリーへの影響を 最小限に 抑えることができます ウィジェットが App内で まだ満たされていないような 明確なユーザー条件を 必要とする場合にも有効です 例えば サービスへのログインや 特定のコンテンツの購入などが 必要な場合にも Neverは最適です このような条件が揃うまで 意味のある情報を提供できない場合 neverを検討されると良いでしょう neverポリシーを使用する ウィジェットの例に TV メモ 音楽 Podcast 連絡先などがあります これらのウィジェットや Appは コンテンツの変更を 促すために App内での ユーザー操作を必要としたり コンテンツの更新のプッシュ 通知を受け取けとります タイムラインエントリを 活用しましょう ウィジットに適した リロードポリシーを選択し WidgetCenterのreload APIを使用し 個別の イベントでタイムラインを リロードしてください では関連性における プレゼンテーションに移りましょう あなたのウィジェットは iOSやmacOSの 特定の状況で 表示されることがあり ウィジェットの姿が 変わる可能性があります ウィジェットは タイムラインの更新なしに 再レンダリングされることが あります 優れたウィジェットは 常にこれらの プレゼンテーション環境に 適切に適応します ダークモードとライトモード iOS 15に導入された 部分的なプライバシー対応 そして完全なプライバシ― 対応について説明します
WidgetKitは システム設定の 変更に応じて コンテンツを ライトモードとダークモード の間で自動的に移行させます このために SwiftUIの力を借りています では ウィジェットを それぞれの状況で どのように見せたいかを 考えてみましょう ここにライトとダークの 配色の メモとカレンダーの例が あります 忘れてはいけなのが すべてのウィジェットが ライトやダークモードに合わせ 背景やテキストカラーを 変更する必要は ないということです 例えば ミュージックや 株価などのウィジェットなど 色を変更しない ウィジェットもあります あなたのAppデザインが ダークもしくは ライトなスタイルの 高コントラストコンテンツに こだわらない場合は あなたのウィジェットに 適した配色を 自由に選んでください
ウィジェットの 配所変更は Xcode Previewsで プレビューできます systemSmall widgetを ライトモードで プレビューした 簡単な例です
今度は ダークモードです この環境でウィジェットが どのように表示されるか プレビューするために colorScheme環境の オーバーライドを 追加するだけでした 次に示すように ライトとダークモードの システム標準の背景色を 使用する場合は BackgroundStyleを 使用してください
ウィジェットは iOSロック画面など プライバシーに配慮した 環境にも適用されます iOS 15の新機能として ウィジェットでは 部分的なコンテンツ対応が できるようになりました さて これはとても わかりにくいと思います では いったい 何のことか 例をあげて 説明しましょう
特定の口座で 利用可能な残高を表示する 銀行のウィジェットが あったとします このケースは 口座に 128.45ドルあります
ロック画面に移動して デバイスをロックすると このアカウントの残高は iOS 14では表示されます なぜなら WidgetKitには デバイスがロックされた際に 残高情報を動的に消去する 方法がなかったからです しかし iOS 15ではそれが変わりました これらの状況で対応を加える 特定のビューを コンテキストによって マーク可能となりました では その方法をご紹介しましょう privacySensitiveという ビューモディファイアを 残高金額を表すテキストに 挿入するだけです つまり パスコードロック されていないときは ここで見られるように ビューにはまだ 残高が表示されます しかし 今度はデバイスを ロックしてみると 残高表示は隠された つまり 対応が加えられた状態になります
また このモディファイアは hstackやvstackのような コンテナビューを含む どのビューにも 適用できることに 注意してください また コンテナに適用した場合 コンテナ全体が 対応が加えられます
iOS デバイスが パスコードロック状態のとき アクセス不可の完全なデータ 保護を利用するAppの場合 例えば Appがヘルスデータを 使用していてウィジェットの 作成をスキップするか ロック画面に表示する ことにある種の恐れがある場合 この機能はその状況に 適しています
WidgetKitではアクティブな タイムラインコンテンツを プレースホルダコンテンツに 自動的に置き換えます デバイスがパスコード ロックされている場合 コンテンツへの完全な対応を 行う場合に使用します また デバイスがパスコード ロックされている間は 更新を 保留することができます これは ここに示す Default-data-protection entitlementを 使用した場合に可能です タイムラインデータは デバイス上の データクラスの 希望に応じて保存されます 私たちは みなさんのデータ プライバシーを大切にします 最後に 関連性における 位置情報について ウィジェットは Appと同様に 現在の物理的な位置や シンプルに関連する場所などの コンテキスト情報を さまざまな方法で 提供することができます
あなたのAppが 位置情報を使用している場合 ウィジェットでも位置情報を 利用することができます ウィジェットは ホーム画面と Macの通知センターに 複数のインスタンスを 持つことができるため インテント機能を使って 天気ウィジェットを 操作するのと同じように ウィジェットに対して あらかじめ選択された場所や 検索可能な場所を 提供することを 検討してください さて ウィジットで現在地を 取得するには いくつかのステップが 必要になります まず Info.plist に NSWidgetUsesLocation キーを指定する 必要があります これにより ウィジットの Extensionで位置情報を 使用することが システムに通知されます 次に 通常通り CLLocationManagerを 使用します ただし 今回は ウィジェットExtensionの TimelineProvider から使用します ウィジェットが必要とする 解像度を考慮してください 大まかな位置情報を 解決する方が早いからです 超精密な位置情報を 必要としないのであれば より良いユーザー 体験を提供できます 一般的には 位置情報のリクエストが 正確なものであればあるほど 解決には時間がかかります
最後に CLLocationManagerの isAuthorizedForWidgetUpdates APIを使いウィジェットが ロケーション更新に対して 許可されているかどうか 確認できます これにより ユーザーが 位置情報を使用するための ウィジェット権限を 付与したかがわかります パーミッションを 見てみましょう 詳しくはこちらです ウィジェットの ロケーションパーミッション 機能を見てみましょう パーミッションは通常 そのAppコンテナと 共有されます ここでは設定Appから 利用できる位置情報の 一覧が表示されています
ユーザーが”Appの使用中” を選択した場合 ユーザーの位置情報は コンテナAppが フォアグラウンドであるとき またはナビセッション中など Appが使用中である と考えられる状況でのみ ウィジェットで 使用可能になります
ユーザーが”Appまたは ウィジェットを使用中” を選択した場合は ”Appの使用中 " と同様に 位置情報を利用できます ただし ウィジェット固有の 許可が追加されます これにより ウィジェットにおける パーミッションが 最後の閲覧から15分以内であれば 位置情報を受け取れるようになります また これらの2つの パーミッションセットの いずれかで位置情報が 解決できない場合は 代替コンテンツを検討し 利用可能であれば 以前のコンテンツも検討か 単に位置情報が 解決できなかったことを 示すだけです
ユーザーが"常に"を選択した場合 ウィジェットは常に 位置情報にアクセスする 利用可能なパーミッションを 持つことになります 最後に カスタマイズ可能な ウィジェットの作成です ユーザーがウィジェットを パーソナライズするため サイズ 種類 構成について 説明します ウィジェットには 様々なサイズがあります ウィジェットを配置する際に 選択できるように できるだけ多くのサイズを サポートすることをお勧めします デバイス間でサイズに わずかな違いがあります システム標準のパディング マージン テキストスタイル テキストサイズを 使用することをお勧めします
さて iPadを見てみると コンテンツショーケースに 変換されます iPad専用の新しいサイズが iOS 15で追加されました エクストララージと 呼んでいます
ここにあるので よく見ることができます 大きなウィジェットと 同じ高さですが iPadで 利用可能なコンテンツが さらに多く 表示されるようになりました systemLargeファミリーを 既にサポートしている 既存のウィジェット構成に 追加しました デフォルトでは ウィジェットの設定で サポートされている ファミリーを指定しない場合 iOS 15 SDK またはそれ以降で ビルドすると 新しいサイズが 自動的にサポートされます
パーソナライゼーションの 次の軸は ウィジェットの種類です ウィジェットの種類によって データやコンテンツを さまざまな角度から 見ることができます Appで最も効果的な ウィジェットの種類を 考えてみましょう これらの説明の最良の方法は 実際の例をあげることです 以下は時計の例です 左側には 1都市の時間を追跡する City ウィジェットがあります 右側には同じビューで 多数の異なる都市に対応できる World Clock ウィジェットがあります こちらは 株式における別の例です 左側には 株式記号の ウィジェットがあります これは ある銘柄の株価を 表示しています この例では Appleです そして右側には 概要ウィジェットがあります 概要ウィジェットは ユーザーのストックAppに 反映されている 一連の銘柄を表示します 異なる種類のウィジェットを どうやって公開するのか? 複数の種類のウィジェットの 公開は極めて簡単です
先程の株式の例を 使って見ましょう ここでは 左上に シンボルウィジェットと 概要ウィジェットがあります これらを公開するには WidgetBundleオブジェクトで さまざまな ウィジェット構成を返し WidgetBundleに @main属性を含めます とても簡単ですね バンドル内で定義される ウィジェットの順序も 非常に重要であることに 注意してください この順序は ウィジェットが ウィジェットギャラリーに どのように表示されるかを 反映しています ですから 必ず 最初にあげたウィジェットが ヒーローユースケースで あることを確認してください 最後に Appの インストール後に ウィジェットの 可用性を動的に 公開したり撤回したり することはできません ウィジェットのサポートには 時間の経過とともに いくつかの配慮が必要です
カスタマイズ可能性の 最後の軸は 構成を介して行われます そして ウィジェットは 2種類をサポートしています 静的およびインテントベース 構成です 静的ウィジェット構成では ウィジェットインスタンス それぞれに同じコンテンツが 提供されます 前回の株式の概要の例を 思い出してください 各コンテンツは デバイス上の 異なる場所にあっても まったく同じコンテンツを 表示します 静的ウィジェットは 非常にシンプルで ユーザーから構成や セットアップを取得しないため 洗練されたウィジェット 定義になっています
その一方で インテントウィジェット構成では ユーザーが設定した コンテンツを提供します 右側の株式銘柄 ウィジェットをご覧ください このユーザーは様々な インスタンスを設定をし それぞれのインスタンスに 異なる銘柄を表示しています さて これは とても素晴らしいものです ホーム画面上の ウィジェットをスタックに入れ 表示することで スペースを節約できます では どのようにして ユーザが設定行えるのでしょうか ユーザーの視点から見ると システムは関連するUIを すべて提供します インテントをサポートしている場合 編集モードで ウィジェットを タップすると 構成プラッタが表示されます ユーザーが設定できる インテントのパラメータ リストが表示されます この例では シンボルを追跡するための 1つのパラメータがあります その値は現在Apple株の 文字列AAPLとなっています さて ユーザーが パラメータをタップすると 入力コントローラが表示され ユーザーからの入力を得ます 完了するとウィジェットが 自動的に更新されます インテントでできる カスタマイズは多数あります WWDC 2020については 素晴らしい講演があり インテントの設定をしたい方は この後にご紹介します とりあえず インテントに基づいて ウィジェットを コーディングする場合と 静的な構成に基づいて コーディングする場合の 違いを簡単に説明します
静的な構成は 本当にシンプルです TimelineProviderで StaticConfiguration オブジェクトを インスタンス化するだけです これをインテントの 構成と比べてみましょう StaticConfigurationは IntentConfigurationに
TimelineProviderは IntentTimelineProvider に置き換えられている ことだけが違いです 各インターフェースは インテントのサポートのため 若干変更されています これにより タイムラインの データ入力時にユーザーによる構成の インテントを受信できます サポートされている さまざまなデータタイプと 構成UIからの外観など ウィジェットのインテントの 作成と構成の詳細については WWDC 2020の “Widgetに設定と インテリジェンスを追加する” を参照してください
まとめます 優れたウィジェットが どのようにタイムラインの エントリを利用し リロードポリシーをマスター して プレゼンテーションや 潜在的な物理環境に 適応するかを確認しました さまざまなサイズ 種類 構成を提供して ダイナミックで パーソナライズされた体験を ユーザーに提供することを 計画しましょう ありがとうございました
-
-
15:46 - Xcode Previews for Widget Views with Color Scheme Overrides
struct MyWidgetEntryView : View { var date: Date var body: some View { ZStack { Rectangle().fill(BackgroundStyle()) VStack { Text("Hello") } } } } struct MyWidget_Previews: PreviewProvider { static var previews: some View { MyWidgetEntryView(date: Date()) .previewContext(WidgetPreviewContext(family: .systemSmall)) .environment(\.colorScheme, .dark) } }
-
16:34 - Widget Partial Privacy Redactions - Banking Example
struct MyWidgetEntryView : View { var body: some View { ZStack { Rectangle().fill(BackgroundStyle()) VStack(alignment: .leading) { Text("Balance") .font(.largeTitle) .fontWeight(.bold) .foregroundColor(Color.blue) Text("$128.45") .privacySensitive() .font(.title2) .foregroundColor(Color.gray) } } } }
-
23:08 - WidgetBundle Example
struct IndividualSymbolWidget : Widget { var body: some WidgetConfiguration { … } } struct StocksOverviewWidget : Widget { var body: some WidgetConfiguration { … } } @main struct MyWidgetBundle: WidgetBundle { var body: some Widget { // Order of these widgets defines the order in the Widget Gallery IndividualSymbolWidget() StocksOverviewWidget() } }
-
25:43 - Static Widget Configuration Example
@main public struct SampleWidget: Widget { public var body: some WidgetConfiguration { StaticConfiguration(kind: "com.sample.myStaticSampleWidgetKind", provider: Provider()) { entry in SampleWidgetEntryView(entry: entry) } .configurationDisplayName("My Widget") .description("This is an example widget.") } } public struct Provider: TimelineProvider { public func timeline(with context: Context, completion: @escaping (Timeline<Entry>) -> ()) { let entry = SimpleEntry(date: Date()) // TODO: Generate a timeline entry completion(timeline) } }
-
25:55 - Intent Widget Configuration Example
@main public struct SampleWidget: Widget { public var body: some WidgetConfiguration { IntentConfiguration(kind: "com.sample.myIntentSampleWidgetKind", intent: SampleConfigurationIntent.self provider: Provider()) { entry in SampleWidgetEntryView(entry: entry) } .configurationDisplayName("My Widget") .description("This is an example widget.") } } public struct Provider: IntentTimelineProvider { public func timeline(for configuration: SampleConfigurationIntent, with context: Context, completion: @escaping (Timeline<Entry>) -> ()) { let entry = SimpleEntry(date: Date(), configuration: configuration) // generate a timeline completion(timeline) } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。