WWDC Quick Look 💓 By SwiftGGTeam
Create complications for Apple Watch

Create complications for Apple Watch

元の動画を見る

ハイライト

watchOS 7 では、アプリが複数のコンプリケーションを提供できるようになり、一部のグラフィック テンプレートで SwiftUI ビューを使用できるようになりますが、ウォッチフェイスのコンテンツは引き続き ClockKit タイムライン、ファミリー、テンプレートによって駆動されます。

主要内容

Apple Watch アプリは、ユーザーがクリックするのをただ待っているわけにはいきません。ダイヤルはユーザーが最も頻繁に見る場所であり、Complication ではアプリの最新ステータスがそこに表示されます。手首を上げると、次のボート、現在のスコア、カウントダウン、今日の進行状況がすべて表示されます (00:23)。

ClockKit が行うことは、まずアプリにタイムラインを渡すように要求することです。各エントリには有効時間とテンプレートがあります。システムは時間に応じてエントリを自動的に切り替えます。アプリを常に実行する必要はありません。セッションは、このモデルをホエール ウォッチング旅行を使用して説明しています。旅行にはもともと開始時刻と終了時刻がありますが、コンプリケーション エントリは 1 回のみにバインドされており、実際の開始時刻よりも前に表示されるため、ユーザーはボートに乗る時間が与えられます (01:33)。

このセッションでは、watchOS 7 の 2 つの変更も同じリンクに反映されました。グラフィック エクストラ ラージ ファミリがエクストラ ラージ ウォッチフェイスに追加されました。 1 つのアプリで複数のコンプリケーションを提供できます。ホエール ウォッチの例では、さまざまな観測所からの同じアプリ目撃情報、新しい目撃情報を記録するポータル、および全体的な季節データも提供されます (03:05)。 11:47)。

SwiftUI は ClockKit のすべてを置き換えるものではありません。講演では次のように述べられています。「CLKFullColorImageProvider」を使用した追加機能テンプレートには、SwiftUI ビューの代替手段があります。開発者は引き続きタイムラインを提供し、ファミリーを選択し、テンプレートを返す必要がありますが、一部のグラフィック テンプレートに SwiftUI ビューを含めることができます (11:15)。

##詳細

タイムラインを使用して現在および将来の状態を引き渡す

(04:54) CLKComplicationDataSource には必須メソッドが 1 つだけあります: getCurrentTimelineEntry(for:withHandler:)。 「今、文字盤は何を表示すべきか」に答えます。

// CLKComplicationDataSource - Required
class ComplicationController: NSObject, CLKComplicationDataSource {

    func getCurrentTimelineEntry(
        for complication: CLKComplication,
        withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void)
    {
        // Call the handler with the current timeline entry
        handler(createTimelineEntry(forComplication: complication, date: Date()))
    }
}

キーポイント:

  • ComplicationController は、ClockKit がコンテンツをリクエストする際に経由する CLKComplicationDataSource に準拠します。
  • 「コンプリケーション」は文字盤上の特定のインスタンスを表し、後でファミリーと識別子を区別するために使用されます。
  • handlerCLKComplicationTimelineEntry? を受け取ります。エントリには有効時間とテンプレートが含まれます。
  • createTimelineEntry(forComplication:date:) はアプリ独自のカプセル化であり、現在時刻を文字盤に表示できるエントリに変換します。

(05:16) アプリが将来のデータを事前に提供できる場合は、タイムラインの終了日と日付以降のエントリも実装する必要があります。 ClockKit は「limit」に従ってバッチでリクエストを実行し、制限を超えたエントリは破棄されます。

// CLKComplicationDataSource - Timeline Support
extension ComplicationController {

    func getTimelineEndDate(
        for complication: CLKComplication,
        withHandler handler: @escaping (Date?) -> Void)
    {
        handler(timeline(for: complication)?.endDate)
    }

    func getTimelineEntries(
        for complication: CLKComplication,
        after date: Date,
        limit: Int,
        withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void)
    {
       handler(timeline(for: complication)?.entries(after: date, limit: limit))
    }
}

キーポイント:

  • getTimelineEndDate は、このタイムラインがカバーできる長さをシステムに伝えます。
  • getTimelineEntries は、システムに存在する最後のエントリ以降のデータを提供し続けます。
  • date は、システムが持つ最後のタイムライン エントリ時刻です。
  • limit は、今回システムが必要とする最大数です。アプリは一度に複数のエントリを挿入しないでください。

データが完全に無効な場合は、「CLKComplicationServer」の「reloadTimeline(for:)」を呼び出します。既存のエントリがまだ有効であるが、アプリが今後のエントリをさらに提供できる場合は、extendTimeline(for:) を呼び出します。システムは、ユーザーのダイヤルに現在設定されている合併症のみを追跡します。これらのインスタンスは、「activeComplications」またはデータ ソース メソッドのパラメーターから取得されます。 「CLKComplication」オブジェクトを自分で作成しないでください (06:00)。

非常に狭いスペースに収まるようにプロバイダーを使用する

(07:47) 複雑さのスペースは非常に小さいため、テキストの同じ段落が異なるファミリとテンプレートに表示される必要があります。 ClockKit はデータ プロバイダーを使用してデータを表現し、開発者向けにさまざまなレイアウトで表示を処理します。

let longDate: Date = DateComponents(year: 2020, month: 9, day: 23).date ?? Date()
let units: NSCalendar.Unit = [.weekday, .month, .day]
let textProvider = CLKDateTextProvider(date: longDate, units: units)

キーポイント:

  • longDate は表示する日付です。
  • units は、曜日、月、日を表示する最長のケースを指定します。
  • CLKDateTextProvider は、スペースに基づいて完全な日付から短いテキストに段階的にダウングレードします。

(08:49) 相対時間は「CLKRelativeDateTextProvider」を使用します。スピーチで挙げられた例はタイマー スタイルで、アプリが文字列を更新する必要がなく、現在時刻で自動的に更新され、秒単位まで正確になります。

let timerStart: Date =
let units: NSCalendar.Unit = [.hour, .minute, .second]
let textProvider = CLKRelativeDateTextProvider(date: timerStart, style: .timer, units: units)

キーポイント:

  • timerStart は、相対時間計算のターゲット時間です。
  • style: .timer を使用すると、プロバイダーをタイマーとして表示できます。
  • units は、時間、分、秒の表示を制御します。
  • 自動更新時間は ClockKit によって処理され、カウントダウンや残り時間に適しています。

同じ段落では、「CLKTimeTextProvider」、「CLKTimeIntervalTextProvider」、「CLKSimpleTextProvider」、「CLKImageProvider」、「CLKFullColorImageProvider」、「CLKTimeIntervalGaugeProvider」についても言及しています。これらのプロバイダーの共通の目標は、コンテンツをさまざまな文字盤の色やファミリーで表示できるようにすることであり、さまざまなスペース サイズでもシステムによって正しく圧縮および色付けできます (09:01) 10:42)。

記述子を使用して複数のコンプリケーションを宣言する

(12:07) watchOS 7 では、複数のコンプリケーションのサポートが追加されています。関連するメソッドは getComplicationDescriptors(withHandler:) および handleSharedComplicationDescriptors(_:) です。 CLKComplicationDescriptor には、一意の識別子、編集インターフェイス表示の displayName、サポートされるファミリー、およびオプションの userInfo または userActivity が含まれます。

// CLKComplicationDataSource - Multiple Complication Support
extension ComplicationController {
    var descriptors : [CLKComplicationDescriptor] = []
    var dataDict = Dictionary<AnyHashable, Any>()

    for station in data.stations {
        dataDict = [“name": station.name, “shortName": station.shortName]
        descriptors.append(
            CLKComplicationDescriptor(
                identifier: station.name,
                displayName: station.name,
                supportedFamilies: CLKComplicationFamily.allCases,
                userInfo: dataDict))
    }

    descriptors.append(
        CLKComplicationDescriptor(
            identifier: "LogSighting",
            displayName: "Log Sighting",
            supportedFamilies: CLKComplicationFamily.allCases))

    descriptors.append(
        CLKComplicationDescriptor(
            identifier: "SeasonData",
            displayName: "Season Data",
            supportedFamilies: [.graphicRectangular]))

    // Call the handler with the currently supported complication descriptors
    handler(descriptors)
}

キーポイント:

  • 各ステーションはディスクリプタとなり、識別子と表示名はステーション名を使用します。
  • userInfo は、nameshortName などのビジネス データを後続のテンプレート作成段階に持ち込みます。
  • 「LogSighting」は、新しい目撃情報を迅速に記録するためのコンプリケーションで、すべての家族にサポートされています。
  • 全体的な季節データにはより大きなキャンバスが必要なため、SeasonData.graphicRectangular のみをサポートします。
  • 記述子リストが変更された場合、reloadComplicationDescriptors() を呼び出すと、システムはサポート リストを再要求します。

アプリでサポートされなくなったコンプリケーションがユーザーのウォッチフェイスに残っている場合、システムはタイムライン エントリを要求し続けます。セッションでは、開発者が可能な限り有用なコンテンツを提供し続けることが求められます。もう 1 つ対処しなければならないのは「CLKDefaultComplicationIdentifier」です。古いバージョンの Complication と共有ウォッチフェイスが関連データを失うと、システムはこの識別子を使用する可能性があります。 15:59)。

ファミリと識別子によってテンプレートを返す

(17:33) createTimelineEntry は最初にテンプレートを作成し、次にテンプレートと日付を CLKComplicationTimelineEntry にパッケージ化します。

func createTimelineEntry(
    forComplication complication: CLKComplication,
    date: Date) -> CLKComplicationTimelineEntry?
{
    guard let template = createTemplate(forComplication: complication, date: date) else {
        return nil
    }
    return CLKComplicationTimelineEntry(date: date, complicationTemplate: template)
}

キーポイント:

  • createTemplate は特定の表示スタイルを決定します。
  • テンプレートの作成に失敗した場合、nil が返され、システムに無効なエントリは与えられません。
  • 成功すると、date によってエントリの表示が開始される時間が決まります。
  • complicationTemplate には、最終的にウォッチフェイスに与えられるビジュアルコンテンツが含まれます。

(17:44) Whale Watch の例は (complication.family, complication.identifier) によって分岐します。 SeasonData は、SwiftUI チャートを Graphic Rectangular で返します。 LogSighting はグラフィック サーキュラーで画像とテキストを返します。他の観測ステーションはファミリーに応じて異なるテンプレートを返します。処理できない場合は、デフォルトのテンプレートに戻ります。

func createTemplate(
    forComplication complication: CLKComplication,
    date: Date) -> CLKComplicationTemplate?
{
    var station: Station? = nil
    if let stationName = complication.userInfo?["name"] as? String {
        station = data.stations.first(where: { $0.name == stationName })
    }

    let image = UIImage(named: "Spout-small")!
    let spoutFullColorImageProvider = CLKFullColorImageProvider(fullColorImage: image)
    let logSightingTextProvider = CLKSimpleTextProvider(
        text: "Log Sighting",
        shortText: "Log")

    let defaultTemplate: (CLKComplicationFamily) -> CLKComplicationTemplate = { family -> CLKComplicationTemplate in
      // Return a default complication template for the given family
    }

    switch (complication.family, complication.identifier) {

    case (.graphicRectangular, "SeasonData"):
        return CLKComplicationTemplateGraphicRectangularFullView(
            ChartView(
                seriesData: data.last7DaysSightings,
                seriesColor: .turquoise)

    case (.graphicCircular, "LogSighting"):
        return CLKComplicationTemplateGraphicCircularStackImage(
            line1ImageProvider: spoutFullColorImageProvider,
            line2TextProvider: logSightingTextProvider)

    case (.graphicCircular, _):
        guard let station = station else { return defaultTemplate(.graphicCircular) }
        return CLKComplicationTemplateGraphicCircularView(
            SightingTypeView(station: station))

    case (.graphicCorner, _):
        guard let station = station else { return defaultTemplate(.graphicCorner) }
        return CLKComplicationTemplateGraphicCornerTextImage(
            textProvider: station.timeAndShortLocTextProvider,
            imageProvider: station.whaleActivityFullColorProvider)

    case (.graphicExtraLarge, _):
        guard let station = station else { return defaultTemplate(.graphicExtraLarge) }
        return CLKComplicationTemplateGraphicExtraLargeCircularStackText(
            line1TextProvider: station.timeAndLocationTextProvider,
            line2TextProvider: station.shortLocationTextProvider)

    default:
        return defaultTemplate(complication.family)
    }
}

キーポイント:

  • complication.userInfo?["name"] は、記述子によってもたらされるステーション名を読み取ります。
  • Graphic ファミリのフルカラー イメージ用の CLKFullColorImageProvider
  • CLKSimpleTextProvider は、長いテキストと短いテキストの両方を LogSighting に提供します。
  • 「switch」は、異なるファミリーの間違ったテンプレートで同じ識別子が使用されることを避けるために、ファミリーと識別子を同時に調べます。
  • デフォルトのテンプレートは、デフォルトの合併症識別子を含む未知のケースを処理します。

重要ポイント

1.「次のアクション」ダイヤルエントリを作成します。

  • 何をすべきか: 次の会議、次のバス、次の薬、または次の潮汐を文字盤に表示し、実際の開始時刻よりも早くエントリが表示されるようにします。
  • 実行する価値がある理由: セッションのホエール ウォッチング タイムラインでは、コンプリケーション エントリが表示される前にイベントの開始を待つ必要がなく、ユーザーが事前に時間を準備できることが説明されています。
  • 開始方法: ビジネス イベントを CLKComplicationTimelineEntry に変換し、getTimelineEntries(after:limit:withHandler:) を使用して将来のエントリを提供します。

2. 同じアプリの複数のデータ ディメンションを分離する

  • 何をすべきか: スポーツ アプリでは、「現在の心拍数」、「今日の進捗状況」、「記録の開始」の 3 つのコンプリケーションが同時に提供されます。
  • 実行する価値がある理由: watchOS 7 では、単一のアプリで複数の CLKComplicationDescriptor を宣言できます。また、Whale Watch の例では、観測ステーション、記録エントリ、および季節データも分離しています。
  • 開始方法: getComplicationDescriptors(withHandler:) で各次元に識別子を割り当て、userInfo を使用して後続のレンダリングに必要なデータを渡します。

3. プロバイダーを使用して同じコンテンツを複数のファミリーに適応させる

  • 対処法: 同じカウントダウンにより、大きな文字盤にフルタイムが表示され、コーナーの小さなマーカーで自動的に時間が短縮されます。
  • 実行する価値がある理由: CLKDateTextProviderCLKRelativeDateTextProvider は、スペースに基づいて適切なテキストを選択し、手書きレイアウトの分岐を減らします。
  • 開始方法: まずテキスト、画像、ゲージを ClockKit プロバイダーにカプセル化してから、プロバイダーを対応するテンプレートに渡します。

4. 共有ウォッチフェイスと古いユーザー向けのフォールバックを準備する

  • 対処方法: ユーザーが古いバージョンのコンプリケーションまたは共有ウォッチフェイスから入力した場合、アプリのアイコン、人気のあるデータ、または元のデフォルト情報が表示されたままになります。
  • 実行する価値がある理由: セッションは CLKDefaultComplicationIdentifier をサポートすることが明示的に必要です。サポートしないと、ウォッチフェイスに壊れたコンプリケーションが表示される可能性があります。
  • 開始方法: テンプレートに論理 default ブランチを作成して、認識可能なデフォルト テンプレートを返します。空のコンテンツを直接返さないでください。

5. キャンバスが最も必要な場所で SwiftUI を使用する

  • やるべきこと: 過去 7 日間の記録、傾向、完了など、長方形のグラフィック ファミリ用の小さなグラフを作成します。
  • 実行する価値がある理由: セッションの例では、SeasonData.graphicRectangular ブランチにある CLKComplicationTemplateGraphicRectangularFullView を使用して、SwiftUI チャートをホストします。
  • 開始方法: まず .graphicRectangular のみをサポートする記述子を定義し、次に (family, identifier) ブランチで対応する SwiftUI テンプレートを返します。

関連セッション

コメント

GitHub Issues · utterances