Swift watchOS 文字盤に情報を表示する

文字盤にコンプリケーションでアイコンを追加し、アプリを起動できるようになったので、コンプリケーションにデータを表示してみる。

1.タイムラインエントリーを作成する

  • アプリ固有のデータをテンプレートにまとめ、そのテンプレートに対してタイムラインエントリーを作成します。
  • ClockKitは定期的にコンプリケーションのデータソースからタイムラインエントリーを要求します。
  • タイムラインエントリーは、アプリのデータで設定したコンプリケーションテンプレートと、ClockKitがそのテンプレートを表示するタイミングを指定する日付で構成されます。
  • データソースはアプリ固有のデータをClockKitが画面上に表示できるようなテンプレートにパッケージします。
  • テンプレートを作成するには、提供されたCLKComplicationオブジェクトを調べ、適切なテンプレートを選択し、アプリからのデータをテンプレートに入れ、テンプレートのタイムラインエントリーを作成します。

1.1 コンプリケーションオブジェクトを調べる

  • ClockKit がテンプレートを要求すると、常にコンプリケーションを記述した CLKComplication オブジェクトが提供されます。
  • コンプリケーションは、アプリが定義する識別子と、CLKComplicationFamily列挙型のファミリーを持ちます。
  • 各識別子は、指定されたファミリーの個別のコンプリケーションタイプを定義します。
  • 作成するコンプリケーションの種類を決定するには、識別子を調べます。
  • watchOS 7以降では、アプリはファミリーごとに1つまたは複数のコンプリケーションを提供できます。例えば、天気予報アプリは、Condition、Temperature、Precipitationの各識別子に対して別々のコンプリケーションをサポートすることができます。
switch complication.identifier {
case complicationConditionIdentifier:
    templateOrNil = myGetConditionTemplate(for: family, date: date)
    
case complicationTemperatureIdentifier:
    templateOrNil = myGetTemperatureTemplate(for: family, date: date)
    
case complicationPrecipitationIdentifier:
    templateOrNil = myGetPrecipitationPercentageTemplate(for: family, date: date)

1.2 コンプリケーションファミリー

  • ClockKit フレームワークは、コンプリケーションをファミリーに整理します。
  • 各ファミリーは、コンプリケーションのサイズと形状を定義します。
  • ファミリーを調べると、どの種類のテンプレートが使用できるかがわかります。
  • ファミリーの完全なリストについては、CLKComplicationFamily を参照してください。
switch complication.family {
case .circularSmall:
    // Create a template from the circular small family.
    
case .modularSmall:
    // Create a template from the modular small family.
    
case .modularLarge:
    // Create a template from the modular large family.
    
// Continue with all the templates supported by the specified type.
    
@unknown default:
    print("*** Unknown Complication Family: \(complication.family) ***")
    // Handle the error here.
}

1.2.1 CLKComplicationFamily.circularSmall
Circular Small

circularsmall

1.2.2 CLKComplicationFamily.extraLarge
Extra Large

extralarge

1.2.3 CLKComplicationFamily.modularSmall
Modular Small

modularsmall
1.2.4 CLKComplicationFamily.modularLarge
Modular Large

modularlarge

1.2.5 CLKComplicationFamily.utilitarianSmall
Utilitarian

utilitariansmall
1.2.5 CLKComplicationFamily.utilitarianSmallFlat
Utilitarian
utilitariansmallflat
1.2.6 CLKComplicationFamily.utilitarianLarge
Utilitarian

utilitarianlarge

1.3 テンプレートを埋めるデータプロバイダの作成

  • データ・プロバイダーは生の値を受け取り、それをテンプレート用にフォーマットします。
  • 例えば、CLKSimpleTextProviderは、短い文字列と長い文字列の2つの文字列を受け取ります。
  • 両方を指定すると、ClockKit はテンプレートのサイズに最適な文字列を選択します。
let temperature = myCity.temperature(date)

let nameProvider = CLKSimpleTextProvider(
    text: myCity.name,
    shortText: myCity.abbreviation)

let temperatureProvider = CLKSimpleTextProvider(
    text: "\(longNumberFormatter.string(from: NSNumber(value: temperature)) ?? "Unknown")º F",
    shortText: shortNumberFormatter.string(from: NSNumber(value: temperature)) ?? "??")

CLKRelativeDateTextProviderやCLKTimeIntervalGaugeProviderなど、一部のデータプロバイダーは、コンプリケーションのバックグラウンド実行バジェットに影響を与えずに、時間の経過に伴って自動的にコンプリケーションを更新するものです。

データ・プロバイダーを使用して、テンプレートを作成し、データを入力してください。

let template = CLKComplicationTemplateModularSmallStackText(
    line1TextProvider: temperatureProvider,
    line2TextProvider: nameProvider)

1.3.1 ModularSmall用のテンプレート作成用例

1.3.1.1 CLKComplicationTemplateModularSmallStackText

samallstack

1.3.1.2 CLKComplicationTemplateModularSmallRingText

smallring

1.3.1.3 CLKComplicationTemplateModularSmallColumnsText

smallcolumns

1.4 コンプリケーションのデータを使用する

  • CLKComplicationDescriptor クラスの userInfo および userActivity プロパティを使用すると、コンプリケーションに関する追加データを渡すことができます。
  • このデータを使って、タイムラインエントリの作成を簡単にしたり、アプリ内で特定のシーンを起動したりすることができます。

例えば、Dynamically Define Descriptorsにあるように、ユーザーのお気に入り都市リストから、コンプリケーションのセットを作成することができます。コンプリケーションの識別子をパースする代わりに、都市と天気のデータ型をコンプリケーションのuserInfo辞書に追加することができます。そして、タイムラインエントリーを作成するために、テンプレートを選択し充填する前に、辞書からデータを読み取ります。

let city: City
// Read the city id from the complication’s userInfo dictionary.
if let cityID = complication.userInfo?[myCityIDKey] as? String {
 city = myData.lookupCity(byID: cityID) ?? myData.currentCity
} else {
 city = myData.currentCity
}
let nameProvider = CLKSimpleTextProvider(
 text: city.name,
 shortText: city.abbreviation)
// Read the complication type from the userInfo dictionary.
let typeIdentifier = complication.userInfo?[myTypeIdentifierKey] as? String ?? “Undefined”

1.5 タイムラインエントリーオブジェクトの作成

  • テンプレートと希望する日付を使用して、CLKComplicationTimelineEntryオブジェクトを作成します。
  • 現在のタイムラインエントリーの場合、現在時刻と同じかそれ以前の日付を指定する必要があります。
  • 未来のタイムライン項目については、コンプリケーションにデータを表示する日付と時間を指定します。
  • 会議コンプリケーションの場合、開始予定時刻の前に会議に関する情報を表示することができます。
  • 未来のTimelineエントリーの作成について詳しくは、未来のTimelineイベントを読み込むを参照してください。

1.6 未来のタイムラインイベントを読み込む

  • ClockKitは、ユーザーが時計を見たときに即座に利用できるように、複雑機構を事前にレンダリングします。
  • 電力消費を最小限に抑えるには、アプリの現在のデータと将来のエントリを含むタイムラインを作成します。
  • このタイムラインエントリにより、ClockKitはバックグラウンドタスクを追加することなく、自動的にコンプリケーションを更新することができます。

1.7 一括ロードデータ

  • 将来のTimelineエントリーのデータを一括してロードするには、データソースの getTimelineEndDate(for:withHandler:) メソッドを実装して、ハンドラにあなたが作成出来る最後のTimelineエントリーの日付を渡してください。
  • 例えば、ミーティングアプリの場合、ユーザーが最後にミーティングを行った日付を返すかもしれません。
func getTimelineEndDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
 handler(myMeetings.last?.date)
}

次に、データソースの getTimelineEntries(for:after:limit:withHandler:) メソッドを実装してください。

2.実際に試す

APIドキュメントを横断的に読み、まとめながら雰囲気は掴んだので動かしてみる。

getComplicationDescriptors で定義した、identifier: “complication”を、getCurrentTimelineEntry 内部で判定(complication.identifier)してあげて、さらに、complication.family で分岐し、.modularSmallの時に表示する内容をコーディングする。

import ClockKit


class ComplicationController: NSObject, CLKComplicationDataSource {
    
    // MARK: - Complication Configuration

    func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
        let descriptors = [
            CLKComplicationDescriptor(identifier: "complication", displayName: "HealthSample", supportedFamilies: CLKComplicationFamily.allCases)
            // Multiple complication support can be added here with more descriptors
        ]
        
        // Call the handler with the currently supported complication descriptors
        handler(descriptors)
    }

    // MARK: - Timeline Population
    
    func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
        // Call the handler with the current timeline entry
        
        switch complication.identifier {
        case "complication":

            switch complication.family {
            case .circularSmall:
                handler(nil)
                return
            case .modularSmall:
                let img = CLKImageProvider(onePieceImage: UIImage(named: "Complication/Modular")!)
                
                let text = CLKSimpleTextProvider(
                    text: "HealthSample",
                    shortText: "70.0")
                
                let template = CLKComplicationTemplateModularSmallStackImage(
                    line1ImageProvider: img,
                    line2TextProvider: text)
        
                let entry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template);
                handler(entry)

            case .modularLarge:
                handler(nil)
                return
            default:
                handler(nil)
                return
            }
        default:
            handler(nil)
            return
        }
    }
}

適当な画像をAssetsの、今回使用するModularに登録する。

コードから呼び出す場合、UIImage(named: “Complication/Modular”) となる。

complication_assets

前回文字盤に追加した位置のアイコンが、今回追加した画像と、適当に入れたテキストに置き換わった!!

complication_icon

OKOK!

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です