Rechercher dans les applis TV

Les utilisateurs ont souvent des contenus spécifiques en tête lorsqu'ils utilisent une application multimédia sur leur téléviseur. Si votre application contient un vaste catalogue de contenus, la recherche d'un titre spécifique n'est peut-être pas le moyen le plus efficace pour les utilisateurs de trouver ce qu'ils recherchent. Une interface de recherche peut aider les utilisateurs à accéder au contenu qui les intéresse plus rapidement que lorsque vous naviguez sur le Web.

La bibliothèque Android Leanback fournit un ensemble de classes pour activer une interface de recherche standard dans votre application, qui est cohérente avec d'autres fonctions de recherche sur téléviseur et fournit des fonctionnalités telles que la saisie vocale.

Ce guide explique comment fournir une interface de recherche dans votre application à l'aide des classes de la bibliothèque Support Leanback.

Ajouter une action de recherche

Lorsque vous utilisez la classe BrowseFragment pour une interface de navigation multimédia, vous pouvez activer une interface de recherche en tant que partie standard de l'interface utilisateur. L'interface de recherche est une icône qui apparaît dans la mise en page lorsque vous définissez View.OnClickListener sur l'objet BrowseFragment. L'exemple de code suivant illustre cette technique.

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());
}

Remarque:Vous pouvez définir la couleur de l'icône de recherche à l'aide de la méthode setSearchAffordanceColor(int).

Ajouter une entrée de recherche et des résultats

Lorsqu'un utilisateur sélectionne l'icône de recherche, le système appelle une activité de recherche à l'aide de l'intent défini. Pour votre activité de recherche, utilisez une mise en page linéaire contenant un SearchFragment. Ce fragment doit également implémenter l'interface SearchFragment.SearchResultProvider pour afficher les résultats d'une recherche.

L'exemple de code suivant montre comment étendre la classe SearchFragment pour fournir une interface de recherche et des résultats:

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;
    }
}

L'exemple de code précédent est destiné à être utilisé avec une classe SearchRunnable qui exécute la requête de recherche sur un thread distinct. Cette technique empêche les requêtes potentiellement lentes de bloquer le thread de l'interface utilisateur principal.