AdventCalendar
Swift
tvOS
tvOSDay 8

リスト系のインデックスラベルを自作してみる

概要

高速スクロール

tvOS10.2から、スクロールビューが縦に長い場合に、Accelerated Scroll(高速スクロール)という機能が追加されました。
これは、

  • 同じ方向に何度もスワイプ
  • タッチサーフェス右端を上下にスワイプ

のいずれかで発火します。

accelerated-scroll.gif

標準で有効になっていて、無効にはできません。

リスト系のインデックスラベル

さらにUITableViewとUICollectionViewの場合はインデックスラベルをカスタマイズできます。
高速スクロールが始まると以下のdelegateが呼ばれ、適切な値を返すと指定したラベルが表示されます。

Screen Shot 2017-11-03 at 18.24.43.png

上下スワイプで操作すると、ラベルに対応するIndexPathに一気にジャンプしてくれます。とっても便利だと思います。

番組表の再生ボタン割り当て問題

AbemaTVの番組表では、日付の変更のために再生ボタンを使わせています。

datelist.gif

本来であれば再生ボタンは番組表からの直接再生に割り当てたいところですが、現状こういうUXで落ち着いています。
インデックスラベルに日付変更の機能を任せれば、直接再生を解放できそうです。

実際に実装してみた

実際にやってみて気づいたのですが、このラベル、フォントや背景色、表示位置を指定することができません。表示上コンテンツと重なってしまって、とても見づらい感じになってしまいました。
あと半角5文字くらいが限度で、それ以上だとtruncateされてしまいました😇

Screen Shot 2017-11-19 at 11.05.13.png

解決方法

非表示にする

高速スクロールは無効にできませんが、インデックスラベルを非表示にすることはできるようです。
以下の要領で非表示にできます。もちろん番組表のケースではこれだと再生ボタン割り当て問題の解決にはなっていません。

if #available(tvOS 10.2, *) {
    collectionView.indexDisplayMode = .alwaysHidden
}

自作する

というわけで標準のUIが微妙なので、自作しようということになります。
ざっくり仕様をまとめてみるとこんな感じです。

  • 右端のスワイプを検知する
  • インデックスをスクロールしている間もスワイプにスクロールが反応する
  • 右端を上下にドラッグしている間は、スクロールが加速して一気にジャンプする
  • インデックスの表示/非表示は若干lazyに反応する

右端スワイプを検知する

多分課題になるのは「右端のスワイプを検知する」というところだと思いますが、既にこの記事で解決済なので、これを利用してラッパーライブラリを作りました。

https://github.com/toshi0383/GestureTV

作ってみた

このGestureTVを利用して、サクッと以下のようなものを作ってみました。

Nov-23-2017 08-46-40.gif

  • 右端に指がある時に右側のビューを表示してフォーカス更新
  • 右側のビューでフォーカスインデックスが変わったら左側のテーブルビューに反映

という実装になっています。サンプルコードをGestureTVのリポジトリに同梱してありますのでご覧ください。

標準のインデックスラベルの場合、インデックスラベルが出ている時のフォーカスの移動速度がもっと速く、インデックス間のジャンプがもっと楽にできる印象なので、まだまだチューニングの余地はあると思います。

まとめ

リスト系のインデックスラベルを自作してみました。イベントさえ取れれば、あとはなんとかなりそうです。
これで少しは番組表が使いやすくなると良いのですが。