WatchKitのObjectsまとめ

![Xcode-12.4](https://img.shields.io/badge/Xcode-12.4-brightgreen) ![Swift-5.3](https://img.shields.io/badge/Swift-5.3-brightgreen) ![watch0S-7.0](https://img.shields.io/badge/watchOS-7.0-brightgreen)

## はじめに
watchOS のアプリを作ってみようかな？と思って調べているとほぼ記事がなかったので watchOS のアプリで使う Storyboard の Objects についてまとめました。

`UIKit` ではなく `WatchKit` を使います（もしかしたら `SwiftUI` 使えるかも？？）。基本的にはコードでインスタンス生成（`init'()`）ができない模様。ほぼ Storyboard で設定するみたいです。

だいたい `WKInterfaceObject` を継承しており、`func setHidden(_ hidden: Bool)` のようにセッターは用意されているがゲッターがないものが多い。Storyboard での初期設定のみでコードで値を設定できないものも多い。現在値が知りたい場合は別で変数を用意するしかない模様。

基本的にサブクラスをつくることもできない（たぶんそんな複雑なことすることもない）。

（今からなら `SwiftUI` 使うべきかもしれないけど気にしない:innocent:）

ソースはこちら:point_right:　[GitHub](https://github.com/adventam10/SampleWatchKit)

## WKInterfaceController
ほぼ `UIViewController`（これはいつか別記事にまとめたい）。ScrollView のようなものはなくこの中にパーツいっぱい置いていったら勝手にスクロールする模様。

```swift
class WKInterfaceController : NSObject
```

[ドキュメント：WKInterfaceController](https://developer.apple.com/documentation/watchkit/wkinterfacecontroller)

画面表示とかのときに下記メソッドが呼ばれる。

> The super implementation of this method does nothing.

とあるのでとくに `super.willActivate()` とかを中で呼ぶ必要はない模様（デフォで記述がないですし。。。）。

```swift
func awake(withContext: Any?)

func willActivate() 
func didDeactivate()

func didAppear()
func willDisappear()
```

画面遷移には push, modal, next page の３つがある（Storyboard で設定する場合 push と modal は Button か Table からしか接続できない）。

|Push|Modal|Next Page|
| --- | --- | --- |
|![push](https://user-images.githubusercontent.com/34936885/110280555-5b0ec180-801e-11eb-99d8-6dc6294f669f.gif)|![modal](https://user-images.githubusercontent.com/34936885/110280602-72e64580-801e-11eb-9919-df51a9e0d636.gif)|![page](https://user-images.githubusercontent.com/34936885/110280564-6104a280-801e-11eb-9dcd-a9b5a04c7311.gif)|

first -> second に push 遷移して戻ると下記のように呼ばれました。

```
first awake
first willActivate
first didAppear
second awake
first willDisappear
second willActivate
first didDeactivate
second didAppear
second willDisappear
first willActivate
second didDeactivate
first didAppear
```

first -> second に modal 遷移して戻ると下記のように呼ばれました。

```
first awake
first willActivate
first didAppear
second awake
first willDisappear
second willActivate
second didAppear
first didDeactivate
second willDisappear
first willActivate
first didAppear
second didDeactivate
```

next page を設定して first -> second -> first と遷移すると下記のように呼ばれました。

```
first awake
first willActivate
first didAppear
second awake
second willActivate
first willDisappear
first didDeactivate
second didAppear
first willActivate
second willDisappear
second didDeactivate
first didAppear
```

## WKUserNotificationInterfaceController
通知用のやつ。ちょっとまだよくわかってない。。。（こちらをみるといいかも:point_right: [Apple Watchのアプリを開発してみた](https://qiita.com/moriyaman/items/81bb876c20ccf6700e3d#notification)）

```swift
class WKUserNotificationInterfaceController : WKInterfaceController
```

[ドキュメント：WKUserNotificationInterfaceController](https://developer.apple.com/documentation/watchkit/wkusernotificationinterfacecontroller)

## WKHostingController
`SwiftUI` 用。今回は割愛。。。

```swift
class WKHostingController<Body> where Body : View
```

[ドキュメント：WKHostingController](https://developer.apple.com/documentation/swiftui/wkhostingcontroller)

## StoryboardReference
複数の Storyboard をつなぐやつ。iOS のやつと同じ。

## WKInterfaceGroup
`UIStackView` のようなやつ。

![group](https://user-images.githubusercontent.com/34936885/110265251-7f5aa600-7ffe-11eb-8495-64fab4b0a084.png)

```swift
class WKInterfaceGroup : WKInterfaceObject
```

[ドキュメント：WKInterfaceGroup](https://developer.apple.com/documentation/watchkit/wkinterfacegroup)

|Attribute|Description|
| --- | --- |
|Layout|horizontally, vertically, overlap の３つ|
|Insets|パディング|
|Spacing|子 View 同士の余白|
|Background|背景画像|
|Mode|背景画像のコンテンツモード|
|Animate|背景画像がアニメーションするかどうか|
|Color|背景色|
|Radius|角丸（デフォルトは 6 pt）|

## WKInterfaceLabel
だいたい `UILabel` と同じ。

![label](https://user-images.githubusercontent.com/34936885/110265335-a6b17300-7ffe-11eb-90fc-67d9a82424ab.png)

```swift
class WKInterfaceLabel : WKInterfaceObject
```

[ドキュメント：WKInterfaceLabel](https://developer.apple.com/documentation/watchkit/wkinterfacelabel)

## WKInterfaceDate
現在日付を表示するラベル。

![date](https://user-images.githubusercontent.com/34936885/110265366-b4ff8f00-7ffe-11eb-977d-f3407e6364f7.png)

```swift
class WKInterfaceDate : WKInterfaceObject
```

[ドキュメント：WKInterfaceDate](https://developer.apple.com/documentation/watchkit/wkinterfacedate)

|Attribute|Description|
|---|---|
|Format|日付のフォーマット|
|Date|日付の `DateFormatter.Style`|
|Time|時刻の `DateFormatter.Style`|
|Preview|プレビュー用の日付|

コードで設定できるのは下記。

```swift
func setTextColor(_ color: UIColor?)
func setTimeZone(_ timeZone: TimeZone?)
func setCalendar(_ calendar: Calendar?)
```

## WKInterfaceTimer
カウントダウン（アップ）用のラベル（秒数を表示する）。

![timer](https://user-images.githubusercontent.com/34936885/110272748-432f4180-800e-11eb-9699-d34543897511.gif)

```swift
class WKInterfaceTimer : WKInterfaceObject
```

[ドキュメント：WKInterfaceTimer](https://developer.apple.com/documentation/watchkit/wkinterfacetimer)

|Attribute|Description|
|---|---|
|Format|表示のフォーマット|
|Enabled|表示後すぐに開始するかどうか|
|Units|表示する単位（秒、分、時間、日、週、月、年）|
|Preview Secs|プレビュー用の秒数|

コードで設定できるのは下記。

```swift
func setTextColor(_ color: UIColor?)
func setDate(_ date: Date)

func start()
func stop()
```

## WKInterfaceButton
ほぼ `UIButton`。

![button](https://user-images.githubusercontent.com/34936885/110282822-7e3b7000-8022-11eb-86bd-a433bc47ac3a.png)

```swift
class WKInterfaceButton : WKInterfaceObject
```

[ドキュメント：WKInterfaceButton](https://developer.apple.com/documentation/watchkit/wkinterfacebutton)

下記のように `IBAction` に `sender` はない。

```swift
@IBAction func buttonAction() {}
```

`selected` などの `state` はない。`image` もないが `Content` を `Group` に変更すると中に色々置けるようになる。

## WKInterfaceTextField
ほぼ `UITextField`。

![textfield](https://user-images.githubusercontent.com/34936885/110268195-a025fa00-8004-11eb-93cc-c7c8ad1fe4e3.gif)

```swift
class WKInterfaceTextField : WKInterfaceObject
```

[ドキュメント：WKInterfaceTextField](https://developer.apple.com/documentation/watchkit/wkinterfacetextfield)

`IBAction` で入力イベントをとれる。

```swift
@IBAction func textFieldAction(_ value: NSString?) {}
```

入力画面を閉じたときに呼ばれ、キャンセル時は `value` が `nil` になる。

## WKInterfaceSwitch
ほぼ `UISwitch`（ラベル付き）。

![switch](https://user-images.githubusercontent.com/34936885/110265321-a2855580-7ffe-11eb-84d4-34e2ac91e4cb.png)

```swift
class WKInterfaceSwitch : WKInterfaceObject
```

[ドキュメント：WKInterfaceSwitch](https://developer.apple.com/documentation/watchkit/wkinterfaceswitch)

`IBAction` で入力イベントをとれる。

```swift
@IBAction func switchAction(value: Bool) {}
```

## WKInterfaceSlider
ほぼ `UISlider`。

![slider](https://user-images.githubusercontent.com/34936885/110265280-900b1c00-7ffe-11eb-8ced-61913d7d926f.png)

```swift
class WKInterfaceSlider : WKInterfaceObject
```

[ドキュメント：WKInterfaceSlider](https://developer.apple.com/documentation/watchkit/wkinterfaceslider)

`IBAction` で入力イベントをとれる。

```swift
@IBAction func sliderAction(_ value: Float) {}
```

## WKInterfaceMap
地図表示するやつ。`MKMapView` 簡易版（とくにイベントは取得できなさそう？？）。

![map](https://user-images.githubusercontent.com/34936885/110265405-cc3e7c80-7ffe-11eb-9e1b-26268048fda6.png)

```swift
class WKInterfaceMap : WKInterfaceObject
```

[ドキュメント：WKInterfaceMap](https://developer.apple.com/documentation/watchkit/wkinterfacemap)

一度に５つまでアノテーション表示ができる。

メソッド一覧。

```swift
func setShowsUserLocation(_ showsUserLocation: Bool)
func setShowsUserHeading(_ showsUserHeading: Bool)
func setUserTrackingMode(_ mode: WKInterfaceMap.UserTrackingMode, animated: Bool)
func setVisibleMapRect(_ mapRect: MKMapRect)
func setRegion(_ coordinateRegion: MKCoordinateRegion)

func addAnnotation(_ location: CLLocationCoordinate2D, with image: UIImage?, centerOffset offset: CGPoint)
func addAnnotation(_ location: CLLocationCoordinate2D, withImageNamed name: String?, centerOffset offset: CGPoint)
func addAnnotation(_ location: CLLocationCoordinate2D, with pinColor: WKInterfaceMapPinColor)
func removeAllAnnotations()
```

## WKInterfaceSeparator
境界線。色の設定だけできる。

![separator](https://user-images.githubusercontent.com/34936885/110265392-c34dab00-7ffe-11eb-918a-22868f5fcc3e.png)

```swift
class WKInterfaceSeparator : WKInterfaceObject
```

[ドキュメント：WKInterfaceSeparator](https://developer.apple.com/documentation/watchkit/wkinterfaceseparator)

## WKInterfaceTable
テーブル。

![table](https://user-images.githubusercontent.com/34936885/110272550-d3b95200-800d-11eb-830d-f82b5b9e89fd.gif)

```swift
class WKInterfaceTable : WKInterfaceObject
```

[ドキュメント：WKInterfaceTable](https://developer.apple.com/documentation/watchkit/wkinterfacetable)

メソッドとプロパティ一覧。

```swift
func setRowTypes(_ rowTypes: [String])
func setNumberOfRows(_ numberOfRows: Int, withRowType rowType: String)
var numberOfRows: Int { get }
func rowController(at index: Int) -> Any?

func insertRows(at rows: IndexSet, withRowType rowType: String)
func removeRows(at rows: IndexSet)

func scrollToRow(at index: Int)

func performSegue(forRow row: Int)

var curvesAtTop: Bool
var curvesAtBottom: Bool
```

選択時は `WKInterfaceController` の下記が呼ばれる。

```swift
override func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) {}
```

簡易実装。

```swift
final class TableInterfaceController: WKInterfaceController {

    @IBOutlet private weak var table: WKInterfaceTable!
    private var tableDataList = ["Test1", "Test2", "Test3", "Test4", "Test5"]

    override func awake(withContext context: Any?) {
        // RowTypeがたぶんRowのID（Storyboardで設定）
        table.setNumberOfRows(tableDataList.count, withRowType: "Row")
        tableDataList.enumerated().forEach { index, value in
            let row = table.rowController(at: index) as! TableRowController
            row.setText(value)
        }
    }

    override func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) {
        print("didSelect")
    }
}

// UITableViewCellのようなやつ
final class TableRowController: NSObject {

    @IBOutlet private weak var label: WKInterfaceLabel!

    func setText(_ text: String) {
        label.setText(text)
    }
}
```

## WKInterfacePicker
ピッカー（画像と文字列が表示できる）。

![picker](https://user-images.githubusercontent.com/34936885/110276873-74603f80-8017-11eb-9c52-6e6f31513936.gif)

```swift
class WKInterfacePicker : WKInterfaceObject
```

[ドキュメント：WKInterfacePicker](https://developer.apple.com/documentation/watchkit/wkinterfacepicker)

`IBAction` で選択イベントを取得できる。

```swift
@IBAction func pickerAction(_ index: Int) {}
```

メソッド一覧。

```swift
func focus()
func resignFocus()

func setSelectedItemIndex(_ itemIndex: Int)
func setItems(_ items: [WKPickerItem]?)
func setCoordinatedAnimations(_ coordinatedAnimations: [WKInterfaceObject & WKImageAnimatable]?)
func setEnabled(_ enabled: Bool)
```

`setItems` で `WKPickerItem` を設定する。 
`WKPickerItem` には下記が設定できる。

```swift
var title: String?
var caption: String?
var accessoryImage: WKImage?
var contentImage: WKImage?
```

## WKInterfaceImage
ほぼ `UIImageView`。複数画像用意するとパラパラ漫画みたいにアニメーションできる。

![image](https://user-images.githubusercontent.com/34936885/110284452-2eaa7380-8025-11eb-92c6-ec854d61556a.png)

```swift
class WKInterfaceImage : WKInterfaceObject
```

[ドキュメント：WKInterfaceImage](https://developer.apple.com/documentation/watchkit/wkinterfaceimage)

## WKInterfaceActivityRing
HealthKit のアクティビティ表示のやつ。

![ring](https://user-images.githubusercontent.com/34936885/110282377-baba9c00-8021-11eb-8156-d1f0163f962a.png)

```swift
class WKInterfaceActivityRing : WKInterfaceObject
```

[ドキュメント：WKInterfaceActivityRing](https://developer.apple.com/documentation/watchkit/wkinterfaceactivityring)

簡易実装。

```swift
import WatchKit
import Foundation
import HealthKit

final class ActivityRingInterfaceController: WKInterfaceController {

    @IBOutlet private weak var activityRing: WKInterfaceActivityRing!

    override func awake(withContext context: Any?) {
        let activitySummary = HKActivitySummary()
        activitySummary.activeEnergyBurned = HKQuantity(unit: .kilocalorie(), doubleValue: 1500)
        activitySummary.activeEnergyBurnedGoal = HKQuantity(unit: .kilocalorie(), doubleValue: 3000)
        activitySummary.appleExerciseTime = HKQuantity(unit: .minute(), doubleValue: 30)
        activitySummary.appleExerciseTimeGoal = HKQuantity(unit: .minute(), doubleValue: 30)
        activitySummary.appleStandHours = HKQuantity(unit: .count(), doubleValue: 9)
        activitySummary.appleStandHoursGoal = HKQuantity(unit: .count(), doubleValue: 10)

        activityRing.setActivitySummary(activitySummary, animated: true)
    }
}
```

## WKInterfaceMovie
動画表示するやつ（とくにイベントは取得できなさそう？？）。再生ボタン押下で動画再生用のモーダルが表示される。

![movie](https://user-images.githubusercontent.com/34936885/110279705-e424f900-801c-11eb-994c-88ae7c835b63.gif)

```swift
class WKInterfaceMovie : WKInterfaceObject
```

[ドキュメント：WKInterfaceMovie](https://developer.apple.com/documentation/watchkit/wkinterfacemovie)

メソッド一覧。

```swift
func setMovieURL(_ URL: URL)
func setVideoGravity(_ videoGravity: WKVideoGravity)
func setLoops(_ loops: Bool)
func setPosterImage(_ posterImage: WKImage?)
```

簡易実装。

```swift
@IBOutlet private weak var movie: WKInterfaceMovie!

override func awake(withContext context: Any?) {
    let url = Bundle.main.url(forResource: "sample", withExtension: "mov")
    movie.setMovieURL(url!)
}
```

## WKInterfaceInlineMovie
動画表示するやつ（とくにイベントは取得できなさそう？？）。`WKInterfaceMovie` と違い再生用のモーダルは表示せずそのままの画面で動画を再生する。

![inline_movie](https://user-images.githubusercontent.com/34936885/110279858-29492b00-801d-11eb-9786-d718c3cc3201.gif)

```swift
class WKInterfaceInlineMovie : WKInterfaceObject
```

[ドキュメント：WKInterfaceInlineMovie](https://developer.apple.com/documentation/watchkit/wkinterfaceinlinemovie)

メソッド一覧。

```swift
func setMovieURL(_ URL: URL)
func setVideoGravity(_ videoGravity: WKVideoGravity)
func setLoops(_ loops: Bool)
func setAutoplays(_ autoplays: Bool)
func setPosterImage(_ posterImage: WKImage?)

func play()
func playFromBeginning()
func pause()
```

簡易実装（再生ボタンがないので自分で用意して `play` を呼ぶ）。

```swift
@IBOutlet private weak var inlineMovie: WKInterfaceInlineMovie!

override func awake(withContext context: Any?) {
    let url = Bundle.main.url(forResource: "sample", withExtension: "mov")
    inlineMovie.setMovieURL(url!)
    inlineMovie.play()
}
```

## WKInterfaceNowPlayingView
再生中のオーディオを操作する View。

![now_playing](https://user-images.githubusercontent.com/34936885/110277357-6f4fc000-8018-11eb-8ac4-c70f1669f7e4.png)

インターフェースは存在しない模様。Storyboard に置くだけでとくに制御はできない。

[ドキュメント：Adding a Now Playing View](https://developer.apple.com/documentation/watchkit/storyboard_elements/adding_a_now_playing_view)

## WKInterfaceVolumeControl
音量操作するやつ？？ちょっと使い方わからない。。。

![volume](https://user-images.githubusercontent.com/34936885/110281768-a9bd5b00-8020-11eb-820d-a45ec65df652.png)

```swift
class WKInterfaceVolumeControl : WKInterfaceObject
```

[ドキュメント：WKInterfaceVolumeControl](https://developer.apple.com/documentation/watchkit/wkinterfacevolumecontrol)

## WKInterfaceMenu
watchOS 7 で deprecated。Force touch 時に表示されるメニュー。 
watchOS 7 で Force touch が廃止された。

## WKInterfaceMenuItem
watchOS 7 で deprecated。Force touch 時に表示されるメニューのアイテム。 
watchOS 7 で Force touch が廃止された。

## WKInterfaceHMCamera
なにかわかってないので割愛。。。

```swift
class WKInterfaceHMCamera : WKInterfaceObject
```

[ドキュメント：WKInterfaceHMCamera](https://developer.apple.com/documentation/watchkit/wkinterfacehmcamera)

## WKInterfaceSKScene
`SpriteKit` 用のやつ。割愛。。。

```swift
class WKInterfaceSKScene : WKInterfaceObject
```

[ドキュメント：WKInterfaceSKScene](https://developer.apple.com/documentation/watchkit/wkinterfaceskscene)

## WKInterfaceSCNScene
`SceneKit` 用のやつ。割愛。。。

```swift
class WKInterfaceSCNScene : WKInterfaceObject
```

[ドキュメント：WKInterfaceSCNScene](https://developer.apple.com/documentation/watchkit/wkinterfacescnscene)

## WKInterfaceAuthorizationAppleIDButton
「Sign in with Apple」用のボタン。これは割愛。。。

```swift
class WKInterfaceAuthorizationAppleIDButton : WKInterfaceObject
```

[ドキュメント：WKInterfaceAuthorizationAppleIDButton](https://developer.apple.com/documentation/watchkit/wkinterfaceauthorizationappleidbutton)

## WKInterfacePaymentButton
「Buy with Apple Pay」用のボタン。これは割愛。。。

```swift
class WKInterfacePaymentButton : WKInterfaceObject
```

[ドキュメント：WKInterfacePaymentButton](https://developer.apple.com/documentation/watchkit/wkinterfacepaymentbutton)

## ジェスチャ
ジェスチャは４つ。

![gestures](https://user-images.githubusercontent.com/34936885/110268218-ac11bc00-8004-11eb-9fea-4a051092b963.gif)

### WKLongPressGestureRecognizer
ほぼ `UILongPressGestureRecognizer`。

```swift
class WKLongPressGestureRecognizer : WKGestureRecognizer
```

[ドキュメント：WKLongPressGestureRecognizer](https://developer.apple.com/documentation/watchkit/wklongpressgesturerecognizer)

`IBAction` でイベントを取得する。

```swift
@IBAction func handleLongPress(_ gesture: WKLongPressGestureRecognizer) {}
```

### WKPanGestureRecognizer
ほぼ `UIPanGestureRecognizer`。

```swift
class WKPanGestureRecognizer : WKGestureRecognizer
```

[ドキュメント：WKPanGestureRecognizer](https://developer.apple.com/documentation/watchkit/wkpangesturerecognizer)

`IBAction` でイベントを取得する。

```swift
@IBAction func handlePan(_ gesture: WKPanGestureRecognizer) {}
```

### WKSwipeGestureRecognizer
ほぼ `UISwipeGestureRecognizer`。

```swift
class WKSwipeGestureRecognizer : WKGestureRecognizer
```

[ドキュメント：WKSwipeGestureRecognizer](https://developer.apple.com/documentation/watchkit/wkswipegesturerecognizer)

`IBAction` でイベントを取得する。

```swift
@IBAction func handleSwipe(_ gesture: WKSwipeGestureRecognizer) {}
```

### WKTapGestureRecognizer
ほぼ `UIPanGestureRecognizer`。

```swift
class WKTapGestureRecognizer : WKGestureRecognizer
```

[ドキュメント：WKTapGestureRecognizer](https://developer.apple.com/documentation/watchkit/wktapgesturerecognizer)

`IBAction` でイベントを取得する。

```swift
@IBAction func handleTap(_ gesture: WKTapGestureRecognizer) {}
```

## おわりに
これで watchOS 用アプリのレイアウトはだいたいできるはず！

`SwiftUI` 使えるなら使うべきな気もするけど気にしない:innocent:

ソースみてね:blush:　[GitHub](https://github.com/adventam10/SampleWatchKit)