実装してわかった!iOSとはここが違うねtvOS!- その2

f:id:cyberz-dev-writer:20160315200214j:plain

はじめに

どうも。OPENREC事業部でゲーム実況動画共有プラットフォームサービスOPENREC.tviOSエンジニアをしている辰己です。
最近では、有名実況主である胎児(たいちゃんねる)さんやもやかわさんのスプラトゥーン実況動画がアップされて盛り上がっていますので、ぜひAppStoreGooglePlayからダウンロードしてみてくださいね!

さて、tvOSアプリを実装してみてわかったことをまとめた前回に引き続き、今回も実際に実装してみてわかったtvOSでの違いについてまとめていこうと思います。
今回のテーマはズバリ、「検索画面」です!

検索画面

コンテンツをたくさん保有するプロジェクトなら必ずと言っていいいほど開発項目に含まれるのが、今回のテーマである検索画面です。
tvOSにおける検索画面の実装はiOSのときに比べて大きく変わっていたので、結構苦戦しました。なので、そんな方が今後現れないよう、ここにまとめておこうと思います。
解説で使用するサンプルコードはGithubに上げておきました。

実行結果

サンプルを実行してみると、下のようなシンプルな検索画面が表示されます。
次の章からは、この検索画面のプロジェクト構成と具体的な実装内容について説明します。

f:id:cyberz-dev-writer:20160418145831p:plain

プロジェクト構成

今回のプロジェクト構成は以下のようになっております。

SearchViewController-tvOS
     |
     |--- AppDelegate.h
     |    AppDelegate.m
     |
      --- SearchResultViewController.h
          SearchResultViewController.m

検索結果画面(SearchResultViewController)だけ別クラスで用意したシンプルな構成にしています。
それ以外のベースとなるコードはパッと見で分かりやすいようにAppDelegateにまとめました。
.storyboardファイルや.xibファイルは今回は使用していません。
では、次の章からは各ファイルの中身について解説していこうと思います。

SearchResultViewController.h

まずは検索結果画面を用意します。ここで重要なのがUISearchResultsUpdatingl.11プロトコルを宣言しておくことです。
これをしておかないと、検索の際のテーブルのアップデートを行うためのメソッドを実装できません。また、今回は検索バーをテーブルビューのヘッダービューとして設定するため、テーブルビューインスタンスはここで宣言します(l.13)。

SearchResultViewController.m

検索結果画面の実装部分をこのファイル内で行います。先にconstセーフティーゾーンの大きさを定義しておくと指定が楽ですね(l.11, l.12)。また、ナビゲーションバーの高さも同じく定義しておくと良いでしょう(l.13)。iOSではデフォルトの高さが64だったナビゲーションバーもAppleTVでは145もあります。
このファイル内で重要なポイントは - (void)updateSearchResultsForSearchController:(UISearchController *)searchController メソッドの実装ですね。このメソッドは検索バーのテキストフィールドの文字列が変化した時に呼び出され、テーブル内のコンテンツをアップデートするための役割を持ちます。先ほどヘッダーの方で宣言したUISearchResultsUpdatingプロトコル内のメソッドです。
最後に、検索として使用するサンプルデータは - (NSArray *)getAllItems 内(l.96 ~ 114)に書いておきました。

AppDelegate.h

今回はこのファイルを編集する必要はないので、割愛します。

AppDelegate.m

いよいよ本題部分の実装を行っているファイルの解説です。
まずは、先ほど実装した検索結果画面のヘッダー(SearchResultViewController.h)をインポートします(l.10)。
そして、ここからは実際のコードにコメントを付けた形で1行ごとに解説していこうと思います(l.24 ~ 38)。

// 検索結果画面のインスタンスを生成(l.24)
SearchResultViewController *searchResultViewController = [[SearchResultViewController alloc]init];

// **UISearchControllerのインスタンスを検索結果画面を引数として生成**(l.25)
UISearchController *searchController = [[UISearchController alloc]initWithSearchResultsController:searchResultViewController];

// searchResultsUpdaterプロパティにUISearchResultsUpdatingプロトコルを実装したviewControllerを指定(l.26)
searchController.searchResultsUpdater = searchResultViewController;

// 画面の表示中にナビゲーションを表示するように指定(l.27)
searchController.hidesNavigationBarDuringPresentation = NO;

// キーボードのスタイルを指定(l.28)
searchController.searchBar.keyboardAppearance = UIKeyboardAppearanceDark;

// 検索バーのプレースホルダー文字列を指定(l.29)
searchController.searchBar.placeholder = @"";

// 背景色を黒色にする(l.30)
searchController.view.backgroundColor = [UIColor blackColor];

// 検索結果画面のテーブルビューのヘッダービューに検索バーを設定(l.31)
searchResultViewController.tableView.tableHeaderView = searchController.searchBar;

// **UISearchContainerViewControllerのインスタンスをUISearchControllerオブジェクトを引数として生成**(l.32)
UISearchContainerViewController *containerViewController = [[UISearchContainerViewController alloc]initWithSearchController:searchController];

// ナビゲーションバーに表示するタイトルを設定(l.33)
containerViewController.title = @"Search";

// UINavigationControllerのインスタンスをrootViewControllerにUISearchControllerオブジェクトを指定して生成(l.34)
UINavigationController *topNavigationController = [[UINavigationController alloc]initWithRootViewController:containerViewController];

// **ナビゲーションバーのtranslucentプロパティをNOに設定**(l.35)
topNavigationController.navigationBar.translucent = NO;

// ナビゲーションバーの色を指定(l.36)
topNavigationController.navigationBar.barTintColor = [UIColor blackColor];

// ナビゲーションバーに表示するタイトルのフォントと色を指定(l.37, l.38)
[topNavigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor],
                                         NSFontAttributeName : [UIFont fontWithName:@"HirakakuProN-W3" size:57]}];

上記のコードで重要なことは2点です。
1つ目は検索画面を生成するまでには必ず4階層分のViewControllerが必要になるということです(SearchResultViewController -> UISearchController -> UISearchContainerViewController -> UINavigationController)。
UISearchControllerまででUINavigationControllerのrootViewControllerに指定すると、何も表示されなくなってしまいます。UISearchControllerの次には必ずUISearchContainerViewController生成しましょう。
そして、2つ目はナビゲーションバーのtranslucentプロパティをNOに設定することです。
iOS7のときのフラットデザイン化に伴ってデフォルト値がYESになったこのプロパティですが、このプロパティをNOに設定しないと、ナビゲーションバー部分が表示されないんです!
検索画面でナビゲーションバーにタイトルが表示されているAppleTV版YouTubeアプリのような作りにしようと思っていた僕はこのプロパティに救われました。
このことに気がついたのは、iOS7になった時にこのプロパティをNOに設定するとYオリジンの始点がナビゲーションバー分だけ下がるという現象に悩まされたことを思い出したからです。もしかしたらtvOSでも起きるのではと思って設定してみたことが功を奏しました。

最後に

本日はここまでです。これでいつ検索画面を実装してほしいと頼まれても大丈夫ですね。
今回も最後まで読んでいただきありがとうございました!