Apple Watch Programming Guide まとめ その2
これの続き
Apple Watch Programming Guide: Developing for Apple Watch
2015-03-09 初出バージョンのドキュメントまとめ(網羅ではなく適宜省略)
WatchKit Apps
UI Essentials
Assembling Your Storyboard Scenes
Storyboard でのシーンの組み立て
- UIの要素をシーンに追加すると縦にスタックされる
- UIの要素を入れるコンテナの役割をする Group は重要な要素
- Group はネストできる
- Group は背景色か背景画像を設定できる
Accommodating Different Display Sizes
異なるディスプレイサイズへの対応
Updating Your Interface at Runtime
ランタイムでの値を設定と更新
- 視覚的なアピアランスを変更する
- サイズを変更する
- 透明度を変更する
- 表示、非表示する
- ランタイムではオブジェクトの追加と削除、並びの変更はできない。hidden でレイアウトから一時的に取り除く事はできる
- オブジェクトを隠すとトルツメされる
- トルツメなしでオブジェクトを隠すには alpha を0にする
Setting Your App’s Key Color
Key Color について
- Key Color はステータスバーのタイトルとショートルックの通知のアプリ名に適用される
- Storyboard の Global Tint で設定する
Internationalizing Your Interface
- ローカライズは Storyboard の Base Internationalization の機能を使う
- programmatically に指定するケースでは
NSLocalizedString
NSNumberFormatter
NSDateFormatter
などを使う NSLocale
は Apple Watch の設定が使用される
Interface Navigation
画面遷移
- 複数の画面を利用する際、ページベースのUIと階層的なUIはどちらかしか使えない
- どちらもモーダルで表示できる
Implementing a Page-Based Interface
ページベースのUIの実装について
- Storyboard で Interface Controller を置いて relationship を
next page
で接続するとページ化される
- ページのセット(集合)は
init
メソッドなどでreloadRootControllersWithNames:contexts:
メソッドを呼び出して変更する事ができる - 複数ページの中で最初に表示するページを指定するには
init
かawakeWithContext:
でbecomeCurrentPage
メソッドを呼ぶ
Implementing a Hierarchical Interface
階層ベースのUIの実装について
- programmatically に画面遷移を行うには
pushControllerWithName:context:
メソッドを呼ぶ。引数の context でデータを渡す事が推奨される - Storyboard ではボタン、グループ、テーブルの row から push segue を作成する
- 遷移後の画面左上に「戻るボタン」が表示される。これをタップするか画面左端をスワイプする事で画面が閉じる
- programmatically に閉じるには
popController
メソッドを呼ぶ - メインの Interface Controller は dismiss できない
Presenting Interface Controllers Modally
モーダルでの表示について
- modal segue を作成する
presentControllerWithName:context:
メソッドで単一の画面をモーダル表示presentControllerWithNames:contexts:
メソッドでページベースの複数画面をモーダル表示
- モーダル表示の先がページベースになっていればページベースのコントローラをモーダル表示する
- モーダル表示したコントローラの画面左上にはコントローラの title が表示される。title を Done や Close など任意に設定可能。title が設定されていない場合は Cancel と設定される
Interface Objects
インターフェースオブジェクト
- インターフェースオブジェクトは
WKInterfaceObject
クラスやそのサブクラスのインスタンス - インターフェースオブジェクトは View ではない。Apple Watch上に実装されたUIの実際の View とワイヤレス通信をを行うプロキシオブジェクト
- WatchKit ではコントローラからラベルなどに値を設定できるが、値や attributes の取得はできない
Creating an Interface Object
インターフェースオブジェクトの作成
- ランタイムでインスタンスを allocate して initialize する事は無い
- Storyboard に配置して作成する
Configuring Your Interface at Design Time
デザイン時のUIの設定
- デザイン時に
WKInterfaceLabel
のテキスト、色、フォントなどを変更可能
Changing Your Interface at Runtime
ランタイムでのUIの変更
- 初期化のタイミングも含めた Interface Controller が active なタイミングでのみインターフェースオブジェクトを設定可能
init
awakeWithContext:
willActivate
メソッドとコントローラに設定されたアクションメソッドでラベルの値、画像その他のインターフェースの設定を行うWKInterfaceController
の初期化時にはまず super のイニシャライザを呼ぶ- インターフェースオブジェクトに同一の run loop で複数回値を設定したとしても、Apple Watch への送信は最適化され最新の値のみが送信される
- 同一の値を同一のプロパティに送ると重複した呼び出しを発見するためのログメッセージが生成される
Responding to User Interactions
ユーザ操作への対応
WKInterfaceObject | Action Method |
---|---|
Button | - (IBAction)method |
Switch | - (IBAction)method:(BOOL)on |
Slider | - (IBAction)method:(float)value |
Menu Item | - (IBAction)method |
Table | table:didSelectRowAtIndex: |
- Segue が実行される前に WatchKit が
contextForSegueWithIdentifier:inTable:rowIndex:
かcontextsForSegueWithIdentifier:inTable:rowIndex:
を呼び出す - ユーザ操作無しで画面を更新するなら
NSTimer
を使う - ネットワークアクセスや位置情報のモニタリングなどの時間のかかるタスクは親アプリで行うのがベスト。shared container を通じて WatchKit Extension にデータを戻す
Hiding Interface Objects
インターフェースオブジェクトを隠す
- 表示したいオブジェクトは Storyboard ファイルに全て含まれていなければならない。表示内容をデータによってカスタマイズするにはオブジェクトを hide する。hide したオブジェクトはトルツメされる
setHidden:YES
でオブジェクトを隠す
Text and Labels
Using Fonts
フォントの使用
- グランスと通知ではシステムフォントのみ。アプリではカスタムフォントが使える
- WatchKit App と WatchKit Extension のバンドルにフォントファイルをいれて WatchKit App の Info.plist に
UIAppFonts
キーを設定して追加したフォントファイルを指定する - カスタムフォントを使ってテキストを作成するには attributed string を使う。この時 attribute で指定されたフォントが存在しなければシステムフォントが使われる
Managing Text Input
テキストの入力
presentTextInputControllerWithSuggestions:allowedInputMode:completion:
メソッドでテキストの選択肢表示、音声入力、絵文字入力、アニメーション絵文字入力の画面を表示する
Internationalizing Your Text Code
テキストのローカライズ
- Storyboard の Base Internationalization の機能を使う
NSLocalizedString
NSNumberFormatter
NSDateFormatter
を使う
Images
画像について
WKInterfaceImage
クラスは単一の画像かシーケンスイメージをスタンドアロンのコンテンツとして表示するWKInterfaceGroup
WKInterfaceButton
WKInterfaceController
は他のコンテンツの背景画像として画像を表示する
Specifying Your Image Assets
画像アセットの指定
- 可能なら常にPNGを使用する
- 画像はサイズ変更ができないのでインターフェースオブジェクトを
setWidth:
setHeight:
して画像が適切なサイズで表示されるようにする - image assets を使用する
Using Named Images to Improve Performance
名前付き画像の使用によるパフォーマンスの改善
setImageNamed:
setBackgroundImageNamed:
メソッドでバンドル内かデバイスにキャッシュ済みの画像を使用する- 画像データそのものを Apple Watch に転送するより、name の文字列だけ転送する方が時間も短くパワーも使わない
setImage:
setImageData:
setBackgroundImage:
setBackgroundImageData:
は WatchKit Extension から WatchKit App へ画像データをワイヤレスで転送する- Extension で UIImage を作成して使用する時は常に iPhone にある画像オブジェクトを使えるよう前もって Apple Watch にデータを送信しなければならない
- imageNamed: メソッドを使ったとしても UIImage は WatchKit App ではなくて Extension のバンドルから読み込まれ、それを使用する際には Apple Watch にワイヤレスで画像データが転送される事になる
Caching Images on the Device
デバイスの画像キャッシュ
- Extension で作成した画像を頻繁に使用するなら
WKInterfaceDevice
クラスのaddCachedImage:name:
かaddCachedImageWithData:name:
メソッドでキャッシュする WKInterfaceImage
のsetImageNamed:
、WKInterfaceGroup
とWKInterfaceButton
のsetBackgroundImageNamed:
でキャッシュする- アニメーション画像をキャッシュする場合は
animatedImageWithImages:duration:
メソッドで全てのアニメーションフレームを含んだ1つの UIImage を作成してキャッシュする。個々のフレームを個別にキャッシュしない事 - キャッシュにはサイズの制限があって、それぞれアプリには約5MBのキャッシュ領域がある*1
- キャッシュがいっぱいになったら新しいものを追加する前に既存の画像を
removeCachedImageWithName:
かremoveAllCachedImages
で削除しなければならない
Tables
テーブルについて
- シングルカラムの
WKInterfaceTable
- Storyboardではコントローラを追加して Interface Controller の IBOutlet を接続する
- コードではそれぞれの row controller のクラスを定義して初期化時に row を追加する。ユーザによる row の選択にも適切に対応する
Configuring Row Controllers
Row Controllers の設定
- content rows に対して異なる row controllers を使用できる
- row controller には初期状態で1つのグループが入っていてそこにラベル、画像、その他オブジェクトを追加できる
(Storyboard での設定方法は iOS の static tableView と同じ要領で、Storyboard上での階層構成は iOS での UITableViewCell が row controller、ContentView が group オブジェクトにあたる場所にある。ただし役割は iOS とは異なっていて row controller のクラスはNSObject
になっている) - row controller は
NSObject
のサブクラスを作成して IBOutlet付きのプロパティでアウトレットを設定していく。また Storyboard にクラスを設定する際は identifier を設定する(このあたりも UITableViewCell と同じ感じ)
Configuring the Table’s Contents at Runtime
ランタイムでのテーブルのコンテンツの設定
setRowTypes:
かsetNumberOfRows:withRowType:
メソッドで row を作成してrowControllerAtIndex:
で rowController を呼び出して値を設定する (ここはドキュメント内のサンプルコードを見た方が早い)- パフォーマンスのため row の数は20以下が良い。それ以上の場合は「続きを読み込む」のようなコントロールを提供する事を考慮する
- 重要なデータのみを表示するのがベター
Handling Row Selections
Row の選択
- row が選択されると Interface Controller の
table:didSelectRowAtIndex:
メソッドが呼ばれる。ここで新しい Interface Controller を呼び出したり row の内容を更新したりする - テーブル全体を選択不可にしたければ Storyboard上で Selectable オプションをオフに設定する
Context Menus
メニューについて
- Force Touch で呼び出される Interface Controller に応じたメニューで最大4つまで表示可能
- メニュー以外の場所をタップするとキャンセル扱いになる
Designing Your Menu Items
メニューのデザイン
- 画像はテンプレート画像を用いる
Adding a Context Menu to an Interface Controller
メニューの設定方法について
- Storyboard で既存の Interface Controller に設定、または programmatically に追加と削除が可能
- 5つ以上設定可能だが表示されるのは4つまで
addMenuItemWithImage:title:action:
かaddMenuItemWithImageNamed:title:action:
メソッドで追加する
Handling Taps in a Menu Item
メニューの実行
- メニューをタップするとメニュー画面が閉じて設定されたアクションが実行される
Settings
設定について
- 設定は変更頻度の高くないアプリの振る舞いやアピアランスといったものを設定するのに使う。Settings Bundle はiOSアプリ内に入っていて iPhone内の Apple Watch アプリによって表示される
- WatchKit の Settings Bundle は iOS の Settings Bundle と同じように動作する
Creating Your WatchKit Settings Bundle
WatchKit の Settings Bundle の作成
- Xcode のメニューから Select File > New > File で Apple Watch > WatchKit Settings Bundle を選択し、Settings-Watch.bundle をiOSアプリのターゲットに追加。名前は変えてはいけない (WatchKit App や WatchKit Extension ではなくiOSアプリをターゲットにする事に注意)
Enabling Access to Preference Values for Your WatchKit Extension
Extension との設定項目の共有
- shared group container を介してiOSアプリと WatchKit Extension間で設定を共有する
- iOS Appと WatchKit Extension の両方で App Groups を有効にして同じ group identifier を選択する
Root.plist
にApplicationGroupContainerIdentifier
キーを追加して同じ identifier を設定する
Accessing Settings at Runtime
ランタイムでの設定へのアクセス
NSUserDefaults
をinitWithSuiteName:
メソッドで初期化してグループコンテナにアクセスする
続く
*1:WatchKit 公開当初の公式ビデオだと20MBと言っていた