ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
コンプリケーションとウィジェット:リローデッド
watchOSやiOSのロック画面を掘り下げていく、ウィジェットのCode-alongが帰ってきました。WidgetKitの最新の改善点をご確認ください。WidgetKitに加えられた改善により、watchOS上の複雑なコンプリケーションを支え、iPhone用のロック画面用ウィジェットが作成できるようになりました。さらに、最新のSwiftUIビューを組み込んで、一目で理解できるデータ表示をする方法をはじめ、各プラットフォームでコンテンツをレンダリングする方法、ウィジェットやコンプリケーションにて、コンテンツのデザインや操作性をカスタマイズする方法について解説します。
リソース
- Creating accessory widgets and watch complications
- Emoji Rangers: Supporting Live Activities, interactivity, and animations
- WidgetKit
関連ビデオ
WWDC23
Tech Talks
WWDC22
WWDC21
WWDC20
-
ダウンロード
♪メロウな ヒップホップ音楽♪ ♪ こんにちは!Devonです 私はwatchOSチームの エンジニアで 本日はiOSについてお話します iOSチームのエンジニアの Grahamです 本日は watchOSについてお話します WidgetKitに 追加した ロック画面用の アクセサリウィジェットや watchOS用の コンプリケーションが 書けるAPIについて SwiftUIへの追加機能と ともに 両方を一緒に開発する 方法を紹介します ウィジェットや タイムライン リロードに 詳しくない方は 過去のWidgetKitの セッションをご覧ください まず コンプリケーションの歴史と その進化について 続いて ウィジェットや コンプリケーションを 新しい環境で彩る 新しいAPIについて その後 Grahamが 独自のウィジェットの 作成方法と既存の ウィジェットExtensionを watchOSに移行する方法を デモで紹介します 次に これらの小さなビューを 最大限に活用する方法を 紹介します 最後に ウィジェットが 表示される可能性がある場所での プライバシー環境について お話しします コンプリケーションは Watchの文字盤に素早く 一目でわかる情報を表示する watchOSの重要な一部で すぐにアクセスできる 価値の高い情報を提供し タップするとApp内の 関連する場所に移動します watchOS 2で ClockKitによって 独自のコンプリケーションが 作成できるようになりました その後 改善が大きく進み
グラフィックコンテンツと 一連の新しいファミリーと リッチコンプリケーションを watchOS 5に導入しました watchOS 7では SwiftUI コンプリケーションと 複数コンプリケーションを 導入して これまで以上の選択肢の 提供が可能になりました コンプリケーションは WidgetKitによって 再構築され SwiftUIを採用し ウィジェットという形で 一目でわかる コンプリケーション体験を iOSにもたらしました iOS 16とwatchOS 9の WidgetKitを使用すると 両方のプラットフォームで 一目でわかる ウィジェットと コンプリケーションが 構築でき コードを 一度書けば 既存の ホーム画面ウィジェットと インフラ共有が可能です そのために 既存のWidgetFamilyタイプに ”accessory”で始まる 新しいウィジェット ファミリーを追加しました 新しいaccessoryRectangular ファミリーは ClockKitの graphic Rectangularファミリーと 同様 複数行のテキストや 小さなグラフやチャートを 表示できます accessory Circularファミリーは 簡単な情報やゲージ 進捗状況の表示に最適で ClockKitのgraphicCircular ファミリーを置き換えます 新しいaccessoryInlineは watchOSの多くの文字盤に あるテキストのスロットで iOSでは時刻の上に表示 されます インラインスロットには 様々なサイズがあり 活用法は 後ほどご紹介します watchOSに特有なのは
ウィジェットコンテンツの 小さな円形と テキストや ゲージを合わせたaccessory Cornerファミリーです ここではiOSとwatchOS共通の ファミリーに焦点を当てます 新しいwatchOS ファミリーや コンプリケーションの 詳細は「WidgetKitの コンプリケーションによる さらなる前進」をご覧ください カラーとレンダリング モードに移りましょう アクセサリウィジェットは 異なる外観を持つことに お気づきでしょうか アクセサリファミリー ウィジェットの外観は システムで制御されますが レンダリングスタイルに 適用するツールを紹介します ウィジェットの表示には レンダリングモードが 3種類あります フルカラー アクセンテッド バイブラントが適用できます この3種類を表現するため WidgetRenderingMode型を 導入しています この値は WidgetRendering Modeの キーパスで Environmentから アクセスできます コンテンツを条件付きで 変更することで どのモードでも丁度よい 見た目で表示できます watchOSの フルカラーモードでは みなさんの指定通りに コンテンツを表示します 天気のゲージの グラデーションや アクティビティリングの 色など 既存のコンプリケーションでは 多くがフルカラーで表現できます アクセンテッドレンダリングモードでは ビューを2つに分割し それぞれ独立して 色付けします 2つのカラーリンググループは オリジナルの不透明度だけ残して フラットに着色します .widgetAccentable() ビューモディファイアで ビューをグループ化する 方法をシステムに指示したり Widget Rendering Mode 環境の 値に基づいて コンテンツを切り替えて フラット化したときに 完璧な見た目にできます このシステムでは コンテンツの色合いを 自在に変化させられ 反転するものもあります 黒い背景や watchOS 9で新たに追加した フルカラーの背景もあります iOSのバイブラント レンダリングモードでは コンテンツは彩度を落とし ロック画面の背景に 適切な色になります グレースケールの コンテンツを 素材感のある外観に マッピングするシステムです この素材は背後の コンテンツに適応し 環境に合わせて表示されます ロック画面では 鮮やかな レンダリングモードに色味を 持たせる設定もできます 明るい光源色のほとんどは 不透明で明るく仕上がります 暗い光源色は 後ろの背景のボケが 目立たなくなり 少し明るくなる程度にしか 見えません このモードでは 視認性を確保するために 透明な色は避けてください 代わりに 濃い色や黒を使って 視認性を維持しながら さりげないコンテンツを 表示します このようなニュアンスを 表現するため AccessoryWidgetBackground ビューを導入し 円形カレンダーのような 背景が必要なウィジェットに 一貫した背景を与えられます アクセサリウィジェットの ほとんどに 背景はないですが 背景が 付くスタイルもあります 背景表示は さまざまなウィジェット レンダリングモードで 異なる外観になり フェイスまたはロック画面の スタイルに適するよう システムで調整されます これはフルカラーや アクセンテッドの 柔らかい透明感のある表示と 鮮やかな環境での黒で 結果的に輝度が低く ぼかしが多くなります Grahamが ロック画面や コンプリケーション用の 新しいウィジェットを 作るのを 楽しみにしていますよ では 彼に引き継ぎます またお会いしましたね! WWDC2020の 「Widget Code-Along」で おなじみのApp Emoji Rangersに 新しい ウィジェットファミリーの サポートを追加予定です 始める前に 既存のウィジェットフリー プロジェクトをお持ちの方へ 開始するには iOSにすでに存在し watchOSに導入した Widget Extensionの ターゲットを プロジェクトに追加します 今日は新しい ウィジェットの追加や コンプリケーションについて お話しします
Emoji Rangersプロジェクトに ついて続けます このAppは お気に入りのEmoji Rangerを トラッキングし ホーム画面のウィジェットで レンジャーの健康状態や 充電時間を知らせます Emoji Rangerを watchOSに導入し 私たちの手首の上に 持ってきました 今日は新しいウィジェット ファミリーのサポートと Emoji Rangerを 拡張して Watchでウィジェットの Extensionを実現します 早速 Widet Extensionを Watchに搭載してみましょう 既存のiOSターゲットと コードを共有する 新しいwatchOSターゲットを 追加します iOSのWidget Extensionの ターゲットを複製し
より良い名前を付け
バンドル識別子が Watch Appで始まるように 変更して ターゲットをwatchOSとし
新しいExtensionを Watch Appに埋め込みます watchOS上でコードを ビルドする必要があります やってみましょう
EmojiRangerWidgetの コードを見ると システムがコンテンツを リロードする際に使う タイムラインプロバイダや
異なるファミリーのために SwiftUIで コンテンツを生成するビュー
ウィジェットのconfiguration そして Xcodeプレビュー プロバイダがあります Emoji Rangers Appは すでに iOSのホーム画面 ウィジェットに対応済みです system small と medium を 提供していますが ウィジェットのconfigurationで 新しいファミリーを 追加してみます
システムファミリーは Watchで利用できないので プラットフォームマクロで supportedFamiliesを 指定します
プレビュープロバイダで 新しいファミリーの プレビューを追加します
watchOS向けのビルドを 成功させる前に 新しいIntentRecommendation APIを実装します iOSでは Intentsは ウィジェット編集UIで 設定可能ですが watchOSでは事前に 設定されたリストの 提供が必要です IntentTimelineProviderの 新しいレコメンデーション メソッドをオーバーライド するとできます
順調に構築中です プレビューを再開して 円形ウィジェットの 見え方を確認しましょう
小さなウィジェットを 想定したコンテンツは 新しいフォームファクタに うまく収まりません 新しいウィジェット ファミリーは ホーム画面にあるiOSの ウィジェットより小さいため コンプリケーションの コンテンツの考慮が必要です そこでコンプリケーションを 際立たせる 新しいビューについて お話しします そのビューの話題に 移りましょう systemSmallや他の ウィジェットのコードが ありますが accessory Circularケースのコードを 追加してみます アバター だけでもまずは良さそうです
しかしこれはAppへのクイック ショートカットを提供しますが ユーザーには何の情報も 提供しません レンジャーが再び戦闘可能な タイミングを ユーザーに知らせるために エッジの周りにプログレス ビューを追加します
問題は 進捗状況を アニメーション表示するには 連続したタイムラインの エントリが必要なことです 代わりに SwiftUIの 自動更新のProgressViewが 使えます レンジャーが完全に 回復するまで 時間範囲が必要です システムがその進捗を 更新し続けるので タイムラインの入力は 1つで済みます
この方がずっといいですね では 長方形のファミリーを 追加してみましょう
recutangularのプレビューを 選択します スペースに余裕があるので コンプリケーションの ように 3行表示にしてみます まず キャラクターの名前 次にレベルと 完治までの時間 自動更新の dateフィールドを使います キャラクターの名前を 目立たせるため 見出しのフォントスタイルで テキストのサイズを調整し 色を調整する widgetAccentable モディファイアを追加します
他のレンダリングモードで どのように表示されるか 見てみましょう
キャラクターの名前が アクセントカラーに なっています ウィジェットや コンプリケーションが 環境に馴染むよう デフォルトのフォント パラメータを使用し フォントスタイルを 活用します iOSとwatchOSでは フォントの スタイルやサイズが 異なります iOSは 通常のテキストデザイン watchOSは 重厚感のある 丸みを帯びた デザインを採用しています ウィジェットや コンプリケーションは 画面上でほかの要素と 隣り合って表示されます そのため Title Headline Body Captionの フォントスタイルの使用を お勧めします
Xcodeのプレビューによると アバターも追加する余裕が あります
iPhoneで見てみましょう
いい感じですね! 最後に テキストの行と オプションで画像表示する accessoryInlineを 追加しましょう インラインアクセサリは システムが定義する カラーリングとフォントに 従って描画されます プレビューを選択しましょう
ヒーローの名前と回復の カウントダウンを表示します
このテキストは Watch スロットには長すぎます 今こそViewThatFitsを お見せするときです 長いビューも簡潔なビューも 提供できて ViewThatFitsは 切り捨てや切り抜きなしに 利用可能なスペースに 適合する 最初のコンテンツ ビューを選択します テキストを短くしましょう
まだ最短のWatchスロットには 長すぎるかもしれないので アバターを 名前に置き換えるという 第3の選択肢を用意します
その様子を見てみましょう
「SwiftUIによるカスタム レイアウトの作成」の セッションで 詳しくご覧ください 素晴らしい! Emoji Rangersも プライバシーを 享受したいので Devonに戻します 私から プライバシーの話をします ウィジェットの アクティブな状態や コンプリケーションの 説明をしてきました しかし 私たちの プラットフォームでは デバイスがコンテンツを 適応表示しているか または 低輝度状態かを 考慮する必要があります iOSのロック画面では デバイスのロック中でも コンテンツを表示するのが デフォルトの操作で このグリッドの左上のセルが それにあたります これは「設定」で設定でき ユーザーは「通知」と同様に ロック時にウィジェットを 適応表示することを選べます watchOSでは Watchの装着中は デバイスはロック解除 されたままです 非アクティブ時には 常時表示に移行し コンテンツは 低輝度で表示され 更新頻度も 低くなります デフォルトの 低輝度状態では コンテンツは 適応表示されません ロック画面と同様に 常時表示状態でも ユーザーが コンプリケーションの 内容を適応表示できるよう 設定可能です この状態では コンテンツの適応表示と 低輝度の両方に 対応する必要があります このプラットフォームは この4つの状態を カバーします ありうる状態を考慮して コンプリケーションと ウィジェットが 機能するようにします その方法を説明します Watchで ウィジェットは 常時表示のサポートが 必要です Environment値 isLuminanceReducedで コンテンツを常時表示に 対応させます ClockKitから来た場合は すべてのタイムライン エントリに対し常時表示の コンテンツが使えます 常時表示の場合 低い更新周期を サポートするため 時間軸のテキスト表示と 進捗表示は 忠実度が 低いモードに変更されます 対応するためには Environment値を用いて 時間的制約のある コンテンツを削除し 低い更新頻度に コンテンツを最適化します 次は適応表示についてです デフォルトの プライバシーモードでは TimelineProviderが作成した プレースホルダービューの 適応表示バージョンを表示します 機密性の高い要素と そうでなく適応表示の 必要がない要素の両方がある場合 .privacySensitive修飾子で 一部のビューだけ 適応表示するようマークします この例では ウィジェットの 心拍数を適応表示し 画像は適応表示せずに残します これで ロック画面と WidgetKitの コンプリケーション用に 素晴らしいウィジェット を作る準備が整いました 新機能の詳細は 「SwiftUIによるカスタム レイアウトの作成」 をご覧ください 2人:ご視聴 ありがとうございました ♪
-
-
4:07 - widgetAccentable
VStack(alignment: .leading) { Text("Headline") .font(.headline) .widgetAccentable() Text("Body 1") Text("Body 2") }.frame(maxWidth: .infinity, alignment: .leading)
-
5:24 - AccessoryWidgetBackground
ZStack { AccessoryWidgetBackground() VStack { Text("MON") Text("6") .font(.title) } }
-
9:02 - Xcode Previews
EmojiRangerWidgetEntryView(entry: SimpleEntry(date: Date(), relevance: nil, character: .spouty)) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) .previewDisplayName("Circular") EmojiRangerWidgetEntryView(entry: SimpleEntry(date: Date(), relevance: nil, character: .spouty)) .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) .previewDisplayName("Rectangular") EmojiRangerWidgetEntryView(entry: SimpleEntry(date: Date(), relevance: nil, character: .spouty)) .previewContext(WidgetPreviewContext(family: .accessoryInline)) .previewDisplayName("Inline") #if os(iOS)
-
9:38 - recommendations method
return recommendedIntents() .map { intent in return IntentRecommendation(intent: intent, description: intent.hero!.displayString) }
-
11:05 - ProgressView
ProgressView(interval: entry.character.injuryDate...entry.character.fullHealthDate, countdown: false, label: { Text(entry.character.name) }, currentValueLabel: { Avatar(character: entry.character, includeBackground: false) }) .progressViewStyle(.circular)
-
11:26 - Rectangular
case .accessoryRectangular: HStack(alignment: .center, spacing: 0) { VStack(alignment: .leading) { Text(entry.character.name) Text("Level \(entry.character.level)") Text(entry.character.fullHealthDate, style: .timer) }.frame(maxWidth: .infinity, alignment: .leading) Avatar(character: entry.character, includeBackground: false) }
-
14:03 - ViewThatFits
ViewThatFits { Text("\(entry.character.name) is resting, combat-ready in \(entry.character.fullHealthDate, style: .relative)") Text("\(entry.character.name) ready in \(entry.character.fullHealthDate, style: .timer)") Text("\(entry.character.avatar) \(entry.character.fullHealthDate, style: .timer)") }
-
16:18 - isLuminanceReduced
@Environment(\.isLuminanceReduced) var isLuminanceReduced var body: some View { if isLuminanceReduced { Text("🙈").font(.title) } else { Text("🐵").font(.title) } }
-
16:52 - privacySensitive
VStack(spacing: -2) { Image(systemName: "heart") .font(.caption.bold()) .widgetAccentable() Text("\(currentHeartRate)") .font(.title) .privacySensitive() }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。