Muitas vezes, os usuários têm um conteúdo específico em mente ao usar um app de mídia na TV. Se o app tem um catálogo grande de conteúdo, navegar até um título específico pode não ser a forma mais eficiente para o usuário encontrar o que ele está buscando. Uma interface de pesquisa pode ajudar o usuário a encontrar o conteúdo que ele busca de forma mais rápida do que a navegação.
A biblioteca androidx.leanback oferece um conjunto de classes para ativar uma interface de pesquisa padrão no seu app que é consistente com outras funções de pesquisa na TV e que disponibiliza recursos como entrada de texto por voz.
Este guia explica como disponibilizar uma interface de pesquisa no seu app usando classes da Biblioteca de Suporte Leanback.
Adicionar uma ação de pesquisa
Ao usar a classe BrowseFragment para uma interface de navegação de mídia, é possível ativar uma interface de pesquisa como parte padrão da interface do usuário. A interface de pesquisa é um ícone exibido no layout quando View.OnClickListener é definido no objeto BrowseFragment. O exemplo de código a seguir ilustra essa técnica.
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()); }
Observação: é possível configurar a cor do ícone de pesquisa usando o
setSearchAffordanceColor(int)
método.
Adicionar uma entrada de pesquisa e resultados
Quando o usuário seleciona o ícone de pesquisa, o sistema invoca uma atividade de pesquisa usando a
intent definida. Para a atividade de pesquisa, use um layout linear que contém um
SearchFragment.
Esse fragmento também precisa implementar a interface SearchFragment.SearchResultProvider
para exibir os resultados de uma pesquisa.
O exemplo de código a seguir ilustra como estender a classe SearchFragment
para oferecer uma interface de pesquisa e resultados:
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; } }
O código de exemplo anterior deve ser usado com uma classe SearchRunnable
que executa a consulta de pesquisa em outra linha de execução. Essa técnica evita que consultas possivelmente lentas
bloqueiem a linha de execução principal da interface do usuário.