Cerca nelle app per TV

Gli utenti hanno spesso in mente contenuti specifici quando utilizzano un'app multimediale sulla TV. Se la tua app contiene un vasto catalogo di contenuti, la ricerca di un titolo specifico potrebbe non essere il modo più efficiente per gli utenti di trovare ciò che stanno cercando. Un'interfaccia di ricerca può aiutare gli utenti ad accedere ai contenuti che vogliono più velocemente rispetto alla navigazione.

La libreria Androidx di Leanback fornisce un insieme di classi per attivare un'interfaccia di ricerca standard all'interno dell'app che sia coerente con altre funzioni di ricerca sulla TV e che fornisca funzionalità come l'input vocale.

Questa guida illustra come fornire un'interfaccia di ricerca nella tua app utilizzando le classi della libreria di supporto Leanback.

Aggiungi un'azione di ricerca

Quando utilizzi la classe BrowseFragment per un'interfaccia di navigazione multimediale, puoi abilitare un'interfaccia di ricerca come parte standard dell'interfaccia utente. L'interfaccia di ricerca è un'icona che viene visualizzata nel layout quando imposti View.OnClickListener sull'oggetto BrowseFragment. Il seguente codice campione dimostra questa tecnica.

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

Nota: puoi impostare il colore dell'icona di ricerca utilizzando il metodo setSearchAffordanceColor(int).

Aggiungi un input di ricerca e i risultati

Quando un utente seleziona l'icona di ricerca, il sistema richiama un'attività di ricerca utilizzando l'intent definito. Per la tua attività di ricerca, utilizza un layout lineare contenente un SearchFragment. Questo frammento deve implementare anche l'interfaccia SearchFragment.SearchResultProvider per visualizzare i risultati di una ricerca.

Il seguente esempio di codice mostra come estendere la classe SearchFragment per fornire un'interfaccia di ricerca e ottenere risultati:

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

Il codice di esempio precedente è destinato a essere utilizzato con una classe SearchRunnable che esegue la query di ricerca su un thread separato. Questa tecnica impedisce alle query con esecuzione potenzialmente lenta di bloccare il thread dell'interfaccia utente principale.