LIFULL Creators Blog

LIFULL Creators Blogとは、株式会社LIFULLの社員が記事を共有するブログです。自分の役立つ経験や知識を広めることで世界をもっとFULLにしていきます。

Use the focus, Luke :ルーク、フォー"カ"スを使え- tvOS事始め

Apple原理主義者の大坪です。未だにスターウォーズのForceと聞くと「理力」という訳語が頭に浮かぶ私はかなり年をとっています。

いきなり何を言い出したかといえば、あれですよ、新しいApple TV。素敵ですよね。日本にいながらアトランタやノースカロライナのローカルニュースを見られるなんて...(以下Apple TV礼賛が数千行続くが省略)


しかしながら


「わーいApple TVたのしいぞー」と喜んでいる場合ではない。iOSでコードを書く身であれば、その上で動くアプリケーションを作らなければならない。(断言)

Apple TVでアプリを作るには主に二つ方法があるようです。しかしマークアップランゲージが苦手で、WPFでプログラムを書くときですらXAMLを避けるような私にとって選択肢は"Traditional App"しかないでしょう。iOSと同じ「ような」フレームワークを使ってごりごり書くのです。

しかし

書き始めると上の行で「ような」が巨大になっている理由を理解することになる。似て非なるものとまではいいませんが、tvOS上でのアプリ開発はiOS上でのそれとはかなり異なっている点がある。今回はその中で一番大きなものの一つである"Force"じゃなくて"Focus"について書きます。




iOSでアプリを作っていると忘れてしまいますが「画面の任意の場所をユーザが直接操作できる」というのは偉大なことです。これはタッチパネルなしにはありえない。

ではiPhoneが登場する前はどうしていたか?ガラケー上でアプリを作っていた時のことを思い出しましょう。十字キーでもって画面上のハイライトしている部分を動かし、決定キーを押す。何かが実行される。つまりユーザが意図している場所はどこなのか?ということをハイライトで示していたわけです。

さて、あたりまえですがApple TVを接続したTVの画面をタッチしても何も起こりません。操作するためにはSiri Remoteなるリモコンを使う必要がある。そこにはTouch Surfaceがついていますが、ここで直接画面上のボタン等を指定できるわけではない。ガラケーでのハイライトに相当するものは、tvOSではフォーカスと呼ばれています。Touch surfaceをすいすいやることでフォーカス移動し、しかるのちにポンと押す。あたかもガラケー時代に先祖返りしたかのような感覚が味わえます。


つまり


tvOSでアプリを作るということは、このフォーカスと付き合うことでもある。さて、ここで問題です。Touch Surface上であれこれ操作した時フォーカスはどう移動するのでしょうか?


答え:Focus Engineの御心のままに


Focus Engineとは、tvOSでフォーカスの移動を全て司っているUIKitの中のシステムです。我々プログラマーにできることは

「ここにフォーカスを移動させてもらえませんかねえ?」

とお願いすることであり、その結果何が起こるかは Focus Engineの心次第。もちろんFocus Engineは乱数に従ってフォーカスを移動させているわけでは(多分)なく、画面上に配置された部品から「当然考えられるように」移動させるわけです。しかしAppleの開発者向けページに"Debugging Focus Issues"なる項目があるのは故のないことではない。tvOS上でアプリを作ると、ここに書いてあるデバッグ方法を何度も実行することになります。ええい、なぜフォーカスがこの部品に移動しない!と呪いの言葉を吐きながら。


というわけでtvOS上でのアプリ開発第一歩として、「とにかくフォーカス移動させてみる」というのをやります。サンプルプログラムをGithubに置きました。機能はほとんどないのですけど、最初の一歩はこういうシンプルなものがいいですよね?ね?ね?(血走った目で懇願)

ダウンロードして実行してみましょう。Apple TVのアプリといえば、画面の上からにょろっと出てきたり引っ込んだりするタブバー。というわけで無駄にUITabBarControllerを使ったUIViewControllerの切り替えも実装しています。

f:id:nextdeveloper:20151221162157g:plain

さてここで問題です。このタブバーの出し入れはどうやっているでしょう?


答え:Focus Engineの御心のままに


細かいことは省略しますが、とにかくコードの方では何もやっていません。タブバーにフォーカスが移動すればバーがにょろっと出る。Viewにフォーカスが移動すれば引っ込む。わーい自分で何もしなくても動いてくれてうれしいな、と言っていられる期間はそう長くないかもしれません。

さて、次の問題です。First Tabと書かれたタブの項目を選ぶと赤い画面が表示され、Firstと書かれたボタンにフォーカスが当たる。位置関係からして「まあ当然だな」と思うわけですが、場合によってはSecondと書かれたボタンに最初にフォーカスが当たって欲しいこともあるでしょう。どうすればそれができるか?


答え:Focus Engineにお願いする


大事なことなので2度書きますが、ここでできるのは「お願いする」ことであり「命令する」ことではない。その結果何が起こるかを決定するのはFocus Engineなのですが、とにかく「お願い」してみましょう。FirstViewController.swiftをみると16行目からこんな部分があります。

//    override weak var preferredFocusedView: UIView? {
//        return secondButton
//    }

わざとらしいコメントアウトを外し、再度実行するとこんな風に動きます。(First Tabという項目上でタップしています)

f:id:nextdeveloper:20151221161917g:plain

タブバーが引っ込んだ時、Secondと書かれたボタンにフォーカスがあたっています。 ここで何が起こっているか?Focus EngineがFirstViewControllerにpreferredFocusedView(フォーカスを当てて欲しいView)は?と聞き、それに対してsecondButtonと答えているわけです。これによりめでたくタブから"Second"と書かれたボタンにフォーカスが移動する。


ちなみに、ここでFirst Tabにフォーカスがあたった状態から下にスワイプすると、前と同じようにタブバーが消え、Firstボタンにフォーカスが移ります。なんだこれは?と問うてはいけません。*1これは仕様です。First Tab上でタップされた時は「そもそもどっちの方向に行こうとしているかわからない」のでpreferredFocusedViewを尋ねてくれるわけですが、スワイプだと「ああ、下に行きたいわけね」とそのすぐ下にあるViewにフォーカスを移す。preferredFocusedViewに何を書いておこうと、聞く耳持たないわけです。いや、ちょっと待て、それは困る、というのならばFirstボタン自体がフォーカスを受け取れないようにしておいて、一旦Secondボタンにフォーカスが移った後にフォーカス可能にする...とかやりだす。ふと気がつけば足元にフォー"カ"スの暗黒面が大きな口を開けていることに気がつく。


かくのごとく


tvOS上でアプリを作ろうとすれば、どこかでFocusの使い方-お願いの仕方-と向き合う必要がある。Star Wars Episode Vで、フォースを身につけるためルークはヨーダを背負ってあちこち走り回っていました。同じような厳しいトレーニングをするのは自由ですが、そうしてもApple TVのフォーカスを思うように動かすことはできない。

素直にボタンを格子状に並べておけばフォーカスについて悩むこともないのかもしれませんが、それでは面白くない。ではtvOSでの「面白い」とはなんなのか。iOSのアプリとどう違うべきであるのか、については以下次号(続くのか?)

*1:ちなみに私はここで丸一日つぶしました。