사용자는 TV에서 미디어 앱을 사용할 때 특정 콘텐츠를 마음에 두고 있는 경우가 많습니다. 앱에 대규모 콘텐츠 카탈로그가 포함되어 있는 경우 특정 타이틀을 검색하는 방법은 사용자가 원하는 콘텐츠를 찾는 가장 효율적인 방법이 아닐 수 있습니다. 검색 인터페이스는 탐색보다 빠르게 원하는 콘텐츠에 도달할 수 있게 해줍니다.
androidx.leanback 라이브러리는 앱 내에서 TV의 다른 검색 기능과 일관된 표준 검색 인터페이스를 사용할 수 있도록 하는 클래스 집합을 제공하며 음성 입력과 같은 기능을 제공합니다.
이 가이드에서는 Leanback 지원 라이브러리 클래스를 사용하여 앱에 검색 인터페이스를 제공하는 방법을 설명합니다.
검색 작업 추가
미디어 탐색 인터페이스에 BrowseFragment
클래스를 사용하면 검색 인터페이스를 사용자 인터페이스의 표준 부분으로 사용 설정할 수 있습니다. 검색 인터페이스는 BrowseFragment
객체에서 View.OnClickListener
를 설정할 때 레이아웃에 표시되는 아이콘입니다. 다음 샘플 코드는 이 기법을 보여줍니다.
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
클래스와 함께 사용하기 위한 것입니다. 이 기법을 사용하면 실행 속도가 느린 쿼리가 기본 사용자 인터페이스 스레드를 차단하지 않도록 할 수 있습니다.