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 de 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.
Esta lição 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 código de amostra 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 setSearchAffordanceColor(int)
.
Adicionar uma entrada de pesquisa e resultados
Quando o usuário seleciona o ícone de pesquisa, o sistema invoca uma atividade de pesquisa por meio da intent definida.
Sua atividade de pesquisa precisa usar 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.
A amostra 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 acima é um exemplo de classe SearchRunnable
separada, 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.