tvOSアドベントカレンダー1日目担当の @toshi0383 です。2日目も担当だし3日目も担当です。頑張ってやっていきます💪
今回は入門向けにリモコンのイベント取得方法についておさらいします。
初めに言っておくとSiriのAPIはアプリ側に解放されておらずイベントが取れません。
tvOSのUXについては以下の記事がわかりやすいので参考にしてみてください。
http://kudakurage.hatenadiary.com/entry/2017/11/16/113657
クリック系
「クリック」系は以下の2パターンで実装できます。
UIPressのレスポンダチェーン
UIPressのレスポンダチェーンが反応するので、これを利用することもできます。
あまり使っているのを見ないかも。
UIPressType
UIGestureRecognizerにallowedPressTypes
を登録して使います。
登録できるイベントの種類は以下の通りです。
@available(tvOS 9.0, *)
public enum UIPressType : Int {
case upArrow
case downArrow
case leftArrow
case rightArrow
case select
case menu
case playPause
}
それぞれ以下の通りに対応します。
-
upArrow
タッチサーフェスの上端をクリック -
downArrow
タッチサーフェスの下端をクリック -
leftArrow
タッチサーフェスの左端をクリック -
rightArrow
タッチサーフェスの右端をクリック -
select
タッチサーフェスの真ん中あたりをクリック -
menu
MENUボタン -
playPause
Play/Pauseボタン
セルをクリックしたら再生する
例えばセルをクリックしたら再生するのは以下のように実装すればよいということになります。
allowedPressTypes
がなぜか[NSNumber]
なので若干書き方にコツがいります。
class CollectionViewCell: UICollectionViewCell {
private var reuseDisposeBag = DisposeBag()
func configure(_ model: Model) {
reuseDisposeBag = DisposeBag()
let playPauseGesture = UITapGestureRecognizer()
playPauseGesture.allowedPressTypes = [UIPressType.playPause.rawValue as NSNumber]
self.addGestureRecognizer(playPauseGesture)
playPauseGesture.rx.event
.subscribe(onNext: { _ in
PlayerAction.shared.play(model)
})
.disposed(by: reuseDisposeBag)
}
}
スワイプ
タッチサーフェスはスワイプに反応します。
UISwipeGestureRecognizer
単発のスワイプなら、UISwipeGestureRecognizerを使えます。
スワイプは上下左右を指定することができます。
let gr = UISwipeGestureRecognizer(target: self, action: #selector(gesture))
gr.direction = .up
view.addGestureRecognizer(gr)
UITouchのレスポンダチェーンやUIKit.UIGestureRecognizerSubclass
UITouchのレスポンダチェーンを使ったりUIGestureRecognizerをサブクラスすれば、どの方向にどれくらいスワイプしたかやbegan,changed,endedなどの詳細なイベントを取得することができます。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print(touches.first?.location(in: view))
super.touchesBegan(touches, with: event)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
}
タッチ
基本的にタッチサーフェスはちょっと触れただけで反応します。リモコンの上下左右の端をタッチすると、方向キーの役割をして、右端なら右隣の要素へフォーカスが移動します。
UITouchのレスポンダチェーン
単純にどこでもいいからタッチされたとかタッチアップとかを検知するなら先ほども言及したUITouchのレスポンダチェーンで十分です。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print(touches.first?.location(in: view))
super.touchesBegan(touches, with: event)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
}
「タッチサーフェス上の端っこ」の検知
上述の通り、
リモコンの上下左右の端をタッチすると、方向キーの役割をして、右端なら右隣の要素へフォーカスが移動します。
ということになっているんですが、「タッチサーフェス上の端っこ」の検知は、UIKitにはAPIが提供されていません。
UITouchのレスポンダチェーンに通知される座標は、最初に触り始めたところが (0, 0)
になってしまうので、タッチサーフェス上の座標が取れないのです。
これの解決方法については別途記事にします。
まとめ
以上、AppleTVのリモコンのイベント取得方法その1でした。
ここまではiOSと大体一緒ですね。リモコンのイベント取得その2,その3ではより実践的な内容を予定しています。
tvOSアドベントカレンダー、明日は引き続き入門ネタでParallaxエフェクトとはというテーマで書きます。