Поиск в телевизионных приложениях

При использовании мультимедийного приложения на телевизоре пользователи часто имеют в виду конкретный контент. Если ваше приложение содержит большой каталог контента, поиск определенного заголовка может быть не самым эффективным способом для пользователей найти то, что они ищут. Интерфейс поиска может помочь вашим пользователям получить доступ к нужному контенту быстрее, чем при просмотре.

Библиотека androidx.leanback предоставляет набор классов для включения стандартного интерфейса поиска в вашем приложении, который соответствует другим функциям поиска на телевизоре и предоставляет такие функции, как голосовой ввод.

В этом руководстве обсуждается, как обеспечить интерфейс поиска в вашем приложении с помощью классов библиотеки поддержки Leanback.

Добавить действие поиска

Когда вы используете класс BrowseFragment для интерфейса просмотра мультимедиа, вы можете включить интерфейс поиска в качестве стандартной части пользовательского интерфейса. Интерфейс поиска — это значок, который появляется в макете, когда вы устанавливаете View.OnClickListener для объекта BrowseFragment . Следующий пример кода демонстрирует этот метод.

Котлин

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

Ява

@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 , чтобы предоставить интерфейс и результаты поиска.

Котлин

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

Ява

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 , который выполняет поисковый запрос в отдельном потоке. Этот метод предотвращает блокировку основного потока пользовательского интерфейса потенциально медленно выполняемыми запросами.