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
1.2.2 CLKComplicationFamily.extraLarge
Extra Large
1.2.3 CLKComplicationFamily.modularSmall
Modular Small
1.2.4 CLKComplicationFamily.modularLarge
Modular Large
1.2.5 CLKComplicationFamily.utilitarianSmall
Utilitarian
1.2.5 CLKComplicationFamily.utilitarianSmallFlat
Utilitarian
1.2.6 CLKComplicationFamily.utilitarianLarge
Utilitarian
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)) ?? "??")
- CLKSimpleTextProvider
- CLKDateTextProvider
- CLKTimeTextProvider
- CLKRelativeDateTextProvider
- CLKTimeIntervalTextProvider
- CLKImageProvider
- CLKFullColorImageProvider
- CLKSimpleGaugeProvider
- CLKTimeIntervalGaugeProvider
CLKRelativeDateTextProviderやCLKTimeIntervalGaugeProviderなど、一部のデータプロバイダーは、コンプリケーションのバックグラウンド実行バジェットに影響を与えずに、時間の経過に伴って自動的にコンプリケーションを更新するものです。
データ・プロバイダーを使用して、テンプレートを作成し、データを入力してください。
let template = CLKComplicationTemplateModularSmallStackText( line1TextProvider: temperatureProvider, line2TextProvider: nameProvider)
1.3.1 ModularSmall用のテンプレート作成用例
1.3.1.1 CLKComplicationTemplateModularSmallStackText
1.3.1.2 CLKComplicationTemplateModularSmallRingText
1.3.1.3 CLKComplicationTemplateModularSmallColumnsText
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”) となる。
前回文字盤に追加した位置のアイコンが、今回追加した画像と、適当に入れたテキストに置き換わった!!
OKOK!