WWDC Quick Look 💓 By SwiftGGTeam
Complications and widgets: Reloaded

Complications and widgets: Reloaded

元の動画を見る

ハイライト

watchOS チームの Devon と iOS チームの Graham が、iOS 16 と watchOS 9 での WidgetKit の主要な拡張について説明します。主な変更点は、watchOS のコンプリケーションが WidgetKit 上に構築され、iOS 16 ではロック画面にアクセサリ ウィジェットが追加されることです。


主要内容

コンプリケーションの目標は単純明快です。文字盤上で一目で判読できる価値の高い情報をユーザーに提供し、クリックをアプリ内の関連する場所に誘導します (01:07)。これまで、watchOS 開発者は主に ClockKit を中心に作業していました。 iOS 開発者は、ホーム画面ウィジェットに WidgetKit を使用します。 2 組の入り口は似ていますが、コードとメンタル モデルは別のものです。

iOS 16 と watchOS 9 では、これが WidgetKit にマージされます。アップルが与えるWidgetFamily追加したaccessoryRectangularaccessoryCircularaccessoryInline、watchOS には追加の機能もありますaccessoryCorner。最初の 3 つのファミリーは iOS ロック画面と watchOS ウォッチフェイスの両方に表示され、開発者はタイムライン、SwiftUI ビュー、既存のホーム画面ウィジェット インフラストラクチャを共有できます (01:58)。

このセッションでは絵文字レンジャーを例に挙げ、既存の iOS ホーム画面ウィジェットから始めて、同じウィジェット拡張機能を watchOS にコピーし、それを徐々に小さいサイズのファミリーに適応させます。焦点は「大きなウィジェットを縮小する」ことではなく、各サイズでのみ表示される情報を再決定することにあります。円にはアバターと回復の進行状況のみが表示され、長方形には名前、レベル、カウントダウンが表示され、インラインでの使用が表示されます。ViewThatFitsさまざまな幅で適切なテキストを選択します (09:56)。

最後に、ロック画面と常時オンのダイヤルのプライバシー環境に対処する必要があります。デバイスがロックされている場合、iOS ロック画面ではコンテンツが表示または非表示になることがあります。 watchOS を常時オン状態にすると、輝度とリフレッシュ レートが低下します。 WidgetKit によって提供されますisLuminanceReducedそしてprivacySensitive()、同じビューで低輝度とプライバシー マスキングをローカルに調整できるようになります (15:02)。


詳細

1. アクセサリ ファミリを使用して iOS ロック画面と watchOS ウォッチフェイスビューを共有する

(02:11) 新しいアクセサリ ファミリがハングアップしていますWidgetFamily優れた。accessoryRectangular複数行のテキストや小さなグラフに適しています。accessoryCircular短いメッセージ、ダッシュボード、進捗状況に適しています。accessoryInlineは、watchOS では複数の文字盤の位置の上に、iOS では時刻の上に表示されるテキスト行です。

Emoji Rangers は、Xcode プレビューで 3 つのファミリーを同時にプレビューします。

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)

キーポイント:

  • 行 1 は同じものを作成しますEmojiRangerWidgetEntryView、同じタイムラインエントリを入力します。 -.accessoryCircular円形の寸法を使用して、アバター、ダッシュボード、進行状況のコンテンツが内部に収まるかどうかを確認します。 -.accessoryRectangular複数行のテキストと長方形の寸法の画像の組み合わせを確認します。 -.accessoryInline文字サイズの行を使用して、切り詰められるかどうかを確認します。 -#if os(iOS)デモのプラットフォーム ブランチから、その理由は watchOS がすべての iOS システム ファミリをサポートしていないためです (08:38)。

2. widgetAccentable と背景​​適応レンダリング モードを使用する

(03:25) アクセサリ ウィジェットは、フルカラー、アクセント、鮮やかの 3 つのモードでシステムによってレンダリングされます。 watchOS は色を完全に表示でき、コンテンツをアクセント グループと通常のグループに分割することもできます。 iOS ロック画面の鮮やかなモードは、最初に彩度を下げてから、ロック画面の背景に基づいたマテリアル効果にマッピングします。

widgetAccentable()どのコンテンツが強調グループに属するかをシステムに伝えるために使用されます。

VStack(alignment: .leading) {
    Text("Headline")
        .font(.headline)
        .widgetAccentable()
    Text("Body 1")
    Text("Body 2")
}.frame(maxWidth: .infinity, alignment: .leading)

キーポイント:

  • VStack(alignment: .leading)長方形のアクセサリの読み取りスタイルに合わせて、複数行のテキストを左に揃えます。 -Text("Headline")キャラクターの名前やステータスタイトルなどの最も重要な情報です。 -.font(.headline)システム フォント スタイルを使用すると、システムは iOS と watchOS 上で適切なフォント ウェイトとフォント スタイルを提供します (12:22)。 -.widgetAccentable()マークタイトルはアクセントカラーグループに入り、システムはアクセントモードで個別に色付けします。 -frame(maxWidth: .infinity, alignment: .leading)コンテンツを利用可能な幅いっぱいに配置し、長方形領域内の不必要な中央揃えを避けます。

一部のアクセサリには、システム調整された背景が必要です。カレンダー サークル スタイルを使用したセッションのデモAccessoryWidgetBackground

ZStack {
    AccessoryWidgetBackground()
    VStack {
        Text("MON")
        Text("6")
            .font(.title)
    }
}

キーポイント:

  • ZStack背景とテキストを同じ円形領域に重ねます。 -AccessoryWidgetBackground()フルカラー、アクセント、鮮やかなモードに応じて外観を切り替えます。
  • 初めText週を空けて、2 番目の週Text日付の数字を入れます。 -.font(.title)日付番号をメインの視覚的なメッセージにします。

3. watchOS には IntentRecommendation が必要です

(09:12) iOS ウィジェット編集インターフェイスでは、インテントを完全に構成できます。 watchOS では、開発者は事前構成されたリストを提供する必要があります。リライトによる絵文字レンジャーIntentTimelineProviderrecommendationsメソッドはこれらの推奨事項を返します。

return recommendedIntents()
    .map { intent in
        return IntentRecommendation(intent: intent, description: intent.hero!.displayString)
    }

キーポイント:

  • recommendedIntents()これは、プロジェクトがすでに持っている推奨されるインテント ソースです。 -.map { intent in ... }各インテントを watchOS が表示できる推奨事項に変換します。 -IntentRecommendation(intent:description:)インテント自体を編集インターフェイスに表示される説明に関連付けます。 -intent.hero!.displayStringEmoji Rangers のキャラクター構成。この推奨事項がどのヒーローに対応するかをユーザーに伝えるために使用されます。

4. 小さなサイズのインターフェイスは、自動的に更新される ProgressView と日付テキストに依存しています。

(10:37) 円形のアクセサリは、アバターを表示し、エッジの進行状況を使用して回復時間を表現するのに適しています。一般的な方法では、進行状況を維持するためにタイムライン エントリを頻繁に生成する必要があります。 SwiftUIの自動アップデートProgressView日付範囲を受け入れると、システムによって進行状況が更新され続けるため、ここで必要なタイムライン エントリは 1 つだけです。

ProgressView(interval: entry.character.injuryDate...entry.character.fullHealthDate,
             countdown: false,
             label: { Text(entry.character.name) },
             currentValueLabel: {
    Avatar(character: entry.character, includeBackground: false)
})
.progressViewStyle(.circular)

キーポイント:

  • interval:受傷時から完全回復までの閉鎖期間を入力します。 -countdown: falseカウントダウン形式ではなく、間隔で進行することを示します。 -labelキャラクター名を指定して、進行状況ビューに意味ラベルを付けます。 -currentValueLabel現在値エリアをキャラクターのアバターに置き換えます。 -.progressViewStyle(.circular)ラウンドアクセサリーの外観に合わせて進行を調整します。

長方形のアクセサリにはより大きなスペースがあり、3 行の情報とアバターに適しています。

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)
    }

キーポイント:

  • case .accessoryRectangular長方形ファミリに個別のレイアウトを提供します。 -HStack左側にテキスト、右側にアバターを配置します。
  • 1行目はキャラクター名、2行目はレベルを表示します。 -Text(entry.character.fullHealthDate, style: .timer)自動的に更新される日付テキストを使用して残り時間を表示します。 -Avatar(... includeBackground: false)小さな領域に背景を重ねないようにしてください。

5. ViewThatFits を使用してインラインの幅の違いを処理する

(13:13) インライン アクセサリはテキスト行であり、watchOS ウォッチフェイスで使用できる幅は大きく異なります。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)")
}

キーポイント:

  • 初めTextiOS のロック画面や広いウォッチ スロットに適した、最も完全な情報。
  • 2番目Textコピーを短くし、核となる部分をキャラクター名とカウントダウンに保ちます。
  • 三番目Text最も狭いダイヤル位置に対応するには、名前の代わりにアバターを使用します。
  • スペースがあるときにより完全な情報が最初に表示されるように、候補は最長から最短の順に並べられます。

6. 低輝度およびプライバシーマスクは分解して処理する必要があります

(16:18) watchOS 常時オン状態は、低輝度および低リフレッシュ レートになります。開発者が使用できるのは、isLuminanceReduced現在の環境を特定し、時間に敏感なコンテンツを削除し、常時表示に適したコンテンツに置き換えます。

@Environment(\.isLuminanceReduced)
var isLuminanceReduced

var body: some View {
    if isLuminanceReduced {
        Text("🙈").font(.title)
    } else {
        Text("🐵").font(.title)
    }
}

キーポイント:

  • @Environment(\.isLuminanceReduced)SwiftUI 環境から低照度状態を読み取ります。 -if isLuminanceReduced常時オンの低輝度ブランチに入ります。
  • 低輝度ブランチでは、高頻度の更新への依存を避けるために、より多くの静的コンテンツが表示されます。
  • 通常のブランチには完全なコンテンツが表示されます。

プライバシー マスキングは機密情報に適用されます。デフォルトのプライバシー モードでは、プレースホルダーの編集されたバージョンが表示されます。一部のコンテンツのみが機密性の高い場合は、追加できます.privacySensitive()16:52)。

VStack(spacing: -2) {
    Image(systemName: "heart")
        .font(.caption.bold())
        .widgetAccentable()
    Text("\(currentHeartRate)")
        .font(.title)
        .privacySensitive()
}

キーポイント:

  • Image(systemName: "heart")これは心拍数アイコンであり、ユーザーのプライバシーに関する価値は含まれません。 -.widgetAccentable()アイコンをアクセサリのアクセントカラーに合わせます。 -Text("\(currentHeartRate)")特定の心拍数を表示します。この項目は機密データです。 -.privacySensitive()心拍数のテキストのみがマークされ、システムで覆われている場合、アイコンは保持されます。

重要ポイント

  1. **やるべきこと: 既存のホーム画面ウィジェットをロック画面と Apple Watch に拡張します。 ** 価値がある理由: 新しいアクセサリ ファミリと watchOS ウィジェット拡張機能は、既存の WidgetKit タイムラインと SwiftUI ビューを再利用できます。 開始方法: 既存の iOS ウィジェット拡張機能を watchOS ターゲットとしてコピーし、プラットフォーム ブランチで宣言します。supportedFamilies、最初に完了します.accessoryCircular.accessoryRectangular.accessoryInlineプレビュー。

  2. **対処方法: ステートフル アプリに対して循環回復進行状況の複雑さを作成します。 ** 実行する価値がある理由:ProgressView(interval:)これはシステムによって自動的に更新され、体力の回復、集中のタイミング、ゲーム キャラクターの冷却などの時間間隔に適しています。 開始方法: 円形ファミリーにコア アイコンを配置しますcurrentValueLabel、開始時刻と終了時刻を渡しますProgressView(interval:countdown:label:currentValueLabel:)

  3. **何をすべきか: ステータス コピーの 1 行の長さを 3 レベルに書き込みます。 ** 実行する価値がある理由: Inline アクセサリの幅は文字盤やロック画面の位置に応じて変化するため、長い 1 つの文が簡単に切れてしまいます。 開始方法: 使用するViewThatFits「完全な文、短い文、アイコンと時間」の順に候補ビューを提供し、Xcode プレビューで確認します.accessoryInline

  4. **やるべきこと: ロック画面データのプライバシー階層を作成します。 ** 実行する価値がある理由: iOS のロック画面と watchOS の常時オン状態の両方が、他の人に見える環境に表示される可能性があります。 WidgetKit は機密ビューのみのカバーをサポートしています。 開始方法: 心拍数、バランス、メッセージ内容などの特定の値をマークします。.privacySensitive()、アイコン、タイトル、カテゴリ名は表示されたままになります。

  5. **やるべきこと: 常時表示の文字盤用に低輝度バージョンを準備します。 ** 実行する価値がある理由: 常時オンの状態は更新頻度が低いため、時間に依存するテキストと動的な進行状況をダウングレードする必要があります。 開始方法: 読む@Environment(\.isLuminanceReduced)、低輝度ブランチ内のカウントダウン、アニメーション、または急速に変化するデータを削除し、静的なアイコンと要約された状態を残します。


関連セッション

コメント

GitHub Issues · utterances