WWDC Quick Look 💓 By SwiftGGTeam
Principles of great widgets

Principles of great widgets

元の動画を見る

ハイライト

iOS 15 は、WidgetKit に構成可能性、プライバシーに配慮したコントロール、さまざまな環境や場所への適応性をもたらし、同時にウィジェットが関連性があり個人的なものであり続けるように設計原則を更新します。

主な内容

ウィジェットの核となる価値は「一目でわかる」ことです。ユーザーは、ホーム画面、ロック画面 (iOS 16 以降)、またはスマート スタックで重要な情報を取得するためにアプリを開く必要はありません。iOS 15 では、この基盤に 3 つの機能が追加されています。それは、ユーザーがウィジェット コンテンツをカスタマイズできるようにすること、機密情報を保護すること、ウィジェットをさまざまな表示環境に適応させることです。

構成可能性とは、ウィジェットにどのようなコンテンツを表示するかをユーザーが決定できることを意味します。株式ウィジェットはどの株式に焦点を当てるかを選択でき、天気ウィジェットはどの都市に焦点を当てるかを選択できます。iOS 15の導入IntentConfigurationを使用すると、ユーザーはウィジェットを長押しして設定インターフェイスを開き、関心のあるコンテンツを選択できます。

プライバシー感度制御は、「ホーム画面に個人情報を表示すべきではない」という問題を解決します。ユーザーが画面をロックすると、銀行カードの残高は隠される必要があります。iOS 15で利用可能.privacySensitive()Modifier を使用すると、システムはロック画面またはプライバシー モードで機密コンテンツをプレースホルダーに自動的に置き換えます。

環境適応とは、同じウィジェットが異なる場所では異なる方法で表示される可能性があるという事実を指します。ホーム画面の天気ウィジェットには詳細な気温が表示されますが、スマート スタックではアイコンのみが必要な場合があります。iOS 15 ではウィジェットが提供されます。widgetFamilyそしてisPreview開発者がコンテキストに基づいてレイアウトを調整できるようになるまで、環境値を待ちます。

##詳細

Xcode プレビューはダークモードをサポートします

(15:46) ウィジェットの Xcode プレビューは、カラー スキームの明示的な設定をサポートするようになり、明るい効果と暗い効果を同時に簡単にプレビューできるようになりました。

struct MyWidget_Previews: PreviewProvider {
    static var previews: some View {
        MyWidgetEntryView(date: Date())
            .previewContext(WidgetPreviewContext(family: .systemSmall))
            .environment(\.colorScheme, .dark)
    }
}

キーポイント:

  • WidgetPreviewContextウィジェットのサイズシリーズを指定する
  • .environment(\.colorScheme, .dark)ダークモードプレビューに切り替える
  • 複数のプレビュー インスタンスを作成して、異なるサイズと配色を同時に表示できます。

プライバシーの機密性の制御

(16:34) 金融や健康などのカテゴリのウィジェットでは、機密データを表示する必要があることがよくあります。ユーザーが画面をロックすると、この情報は隠される必要があります。

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

キーポイント:

  • .privacySensitive()機密情報が含まれる可能性のあるビューにフラグを設定する
  • システムは、ロック画面やプライバシー モードなどで、プレースホルダーをプレースホルダーに自動的に置き換えます。
  • プレースホルダーは通常、点、四角形、または一般的なアイコンです。
  • 現在プライバシー モードかどうかを手動で判断する必要はありません

WidgetBundle は複数のウィジェットを整理します

(23:08) アプリは複数のウィジェットを提供し、WidgetBundle を通じてそれらを均一に管理できます。

struct IndividualSymbolWidget: Widget {
    var body: some WidgetConfiguration {
        // 配置
    }
}

struct StocksOverviewWidget: Widget {
    var body: some WidgetConfiguration {
        // 配置
    }
}

@main
struct MyWidgetBundle: WidgetBundle {
    var body: some Widget {
        // 这里的顺序决定了 Widget Gallery 中的显示顺序
        IndividualSymbolWidget()
        StocksOverviewWidget()
    }
}

キーポイント:

  • @mainタグ付けされた WidgetBundle は、ウィジェット拡張機能のエントリ ポイントです。
  • バンドル内のウィジェットの順序は、ウィジェット ギャラリー内の順序と一致します。
  • 各ウィジェットは独立した構成と TimelineProvider を持つことができます

静的構成とインテント構成

(25:43) ウィジェットには、静的構成とインテント構成の 2 つの構成方法があります。

// 静态配置 - 适合不需要用户自定义的 Widget
@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())
        completion(timeline)
    }
}
// Intent 配置 - 适合需要用户自定义的 Widget
@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)
        completion(timeline)
    }
}

キーポイント:

  • StaticConfiguration使用TimelineProvider、固定コンテンツを含むウィジェットに適しています
  • IntentConfiguration使用IntentTimelineProvider、ユーザー設定のインテントを渡す必要があります
  • インテント タイプを指定する必要があります.intentdefinitionファイルで定義されている
  • ユーザーはウィジェットを長押しして設定インターフェイスを開き、インテント パラメータを変更できます。

重要ポイント

  1. 複数の都市の天気ウィジェット
  • 何をすべきか: 天気ウィジェットを使用すると、ユーザーはフォローする都市の数と順序を選択できます。
  • 実行する価値がある理由:IntentConfiguration各ユーザーが独自の天気パネルをカスタマイズできるようにする
  • 開始方法:.intentdefinition定義上CityConfigurationIntent都市リストパラメータを含む、プロバイダーはユーザーが選択した都市に基づいて対応するタイムラインを生成します
  1. パーソナル ファイナンス ダッシュボード
  • 対処方法: 画面がロックされている場合、銀行残高ウィジェットは特定の金額を自動的にブロックし、「残高があります」または残高範囲のみを表示します。
  • 実行する価値がある理由:.privacySensitive()1 行のコードで機密情報を保護する
  • 開始方法: 金額を表示するテキストビューに追加します。.privacySensitive()、システムはオクルージョン ロジックを自動的に処理します。
  1. スマートスタッキングアダプティブレイアウト
  • 内容: ニュース ウィジェットはホーム画面にタイトルの概要を表示し、スマート スタックにはカテゴリ アイコンと見出しのみを表示します。
  • 実行する価値がある理由:widgetFamily環境値によって現在のサイズが決定され、情報密度が動的に調整されます。
  • 開始方法: を使用します@Environment(\.widgetFamily)現在のサイズを取得し、@Environment(\.isPreview)プレビュー中かどうかを判断し、環境に応じて異なるビューを返す
  1. 複数株トラッカー
  • 操作方法: 株ウィジェットを使用すると、ユーザーはフォローしている複数の株を追加し、ユーザーが指定した順序で表示できます。
  • 実行する価値がある理由: インテントは配列パラメーターをサポートしており、ユーザーは関心のある銘柄を自由に組み合わせることができます。
  • 開始方法: 定義StockSymbolsIntent含む[String]株式コード配列のタイプ。プロバイダーは配列の内容に基づいてリアルタイムの相場を取得します。
  1. 時間ベースのスケジュールリマインダー
  • 操作方法: カレンダー ウィジェットには時間帯に応じて異なるコンテンツが表示されます。午前中には今日の旅程が表示され、午後には通勤交通状況が表示され、夕方には明日の天気が表示されます。
  • 実行する価値がある理由:TimelineEntry異なる時点に異なるコンテンツを設定可能
  • 開始方法: タイムライン内の異なる時点に対して異なるエントリを生成します。各エントリには、その期間に最も関連性の高い情報が含まれています。

関連セッション

コメント

GitHub Issues · utterances