4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

tvOSAdvent Calendar 2017

Day 1

リモコンのイベント取得その1 クリックとスワイプ

Last updated at Posted at 2017-11-30

tvOSアドベントカレンダー1日目担当の @toshi0383 です。2日目も担当だし3日目も担当です。頑張ってやっていきます💪

tvOSの特徴といえばまずはあのリモコンですよね。
tv.png

今回は入門向けにリモコンのイベント取得方法についておさらいします。
初めに言っておくと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エフェクトとはというテーマで書きます。

参考

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?