ユーザーがテレビでメディアアプリを使用する際、特定のコンテンツを念頭に置いていることがよくあります。アプリ内のコンテンツ カタログが大きい場合、ブラウジングしながら特定のタイトルを探そうとしてもあまり効率的ではなく、探しているコンテンツがなかなか見つからないことがあります。検索インターフェースがあれば、ユーザーは、ブラウジングしながらの場合よりも早く目的のコンテンツにたどり着くことができます。
Leanback AndroidX ライブラリは、アプリ内で標準の検索インターフェースを使用できるようにするクラスのセットを提供します。この検索インターフェースは、テレビの他の検索機能と整合性があり、音声入力などの機能も備えています。
このレッスンでは、Leanback サポート ライブラリ クラスを使用して、アプリ内で検索インターフェースを提供する方法について説明します。
検索アクションを追加する
メディア ブラウジング インターフェースに対して BrowseFragment
クラスを使用すると、ユーザー インターフェースの標準部分として検索インターフェースを有効にできます。検索インターフェースは、レイアウト内に表示されるアイコンで、View.OnClickListener
を BrowseFragment
オブジェクトに対して設定したときに表示されます。この方法を次のサンプルコードに示します。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.browse_activity) browseFragment = fragmentManager.findFragmentById(R.id.browse_fragment) as BrowseFragment browseFragment.setOnSearchClickedListener { view -> val intent = Intent(this@BrowseActivity, SearchActivity::class.java) startActivity(intent) } browseFragment.setAdapter(buildAdapter()) }
Java
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.browse_activity); browseFragment = (BrowseFragment) getFragmentManager().findFragmentById(R.id.browse_fragment); ... browseFragment.setOnSearchClickedListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(BrowseActivity.this, SearchActivity.class); startActivity(intent); } }); browseFragment.setAdapter(buildAdapter()); }
注: setSearchAffordanceColor(int)
を使用すると、検索アイコンの色を設定できます。
検索入力と検索結果を追加する
ユーザーが検索アイコンを選択すると、定義済みインテントを通じて検索アクティビティが呼び出されます。
検索アクティビティでは、SearchFragment
を含む線形レイアウトを使用する必要があります。また、このフラグメントでは、検索結果を表示するために SearchFragment.SearchResultProvider
インターフェースを実装する必要があります。
SearchFragment
クラスを拡張して検索インターフェースと検索結果を提供する方法を次のサンプルコードに示します。
Kotlin
class MySearchFragment : SearchFragment(), SearchFragment.SearchResultProvider { private val rowsAdapter = ArrayObjectAdapter(ListRowPresenter()) private val handler = Handler() private val delayedLoad = SearchRunnable() val resultsAdapter: ObjectAdapter get() { return rowsAdapter } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setSearchResultProvider(this) setOnItemClickedListener(getDefaultItemClickedListener()) } fun onQueryTextChange(newQuery: String): Boolean { rowsAdapter.clear() if (!TextUtils.isEmpty(newQuery)) { delayedLoad.setSearchQuery(newQuery) handler.removeCallbacks(delayedLoad) handler.postDelayed(delayedLoad, SEARCH_DELAY_MS) } return true } fun onQueryTextSubmit(query: String): Boolean { rowsAdapter.clear() if (!TextUtils.isEmpty(query)) { delayedLoad.setSearchQuery(query) handler.removeCallbacks(delayedLoad) handler.postDelayed(delayedLoad, SEARCH_DELAY_MS) } return true } companion object { private val SEARCH_DELAY_MS = 300 } }
Java
public class MySearchFragment extends SearchFragment implements SearchFragment.SearchResultProvider { private static final int SEARCH_DELAY_MS = 300; private ArrayObjectAdapter rowsAdapter; private Handler handler = new Handler(); private SearchRunnable delayedLoad; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter()); setSearchResultProvider(this); setOnItemClickedListener(getDefaultItemClickedListener()); delayedLoad = new SearchRunnable(); } @Override public ObjectAdapter getResultsAdapter() { return rowsAdapter; } @Override public boolean onQueryTextChange(String newQuery) { rowsAdapter.clear(); if (!TextUtils.isEmpty(newQuery)) { delayedLoad.setSearchQuery(newQuery); handler.removeCallbacks(delayedLoad); handler.postDelayed(delayedLoad, SEARCH_DELAY_MS); } return true; } @Override public boolean onQueryTextSubmit(String query) { rowsAdapter.clear(); if (!TextUtils.isEmpty(query)) { delayedLoad.setSearchQuery(query); handler.removeCallbacks(delayedLoad); handler.postDelayed(delayedLoad, SEARCH_DELAY_MS); } return true; } }
上記のサンプルコードは、別のスレッドで検索クエリを実行する別の SearchRunnable
クラスと一緒に使用することを想定しています。この方法により、実行速度の遅いクエリがメイン ユーザー インターフェース スレッドをブロックするのを防ぐことができます。