Поиск по содержимому в RecyclerView

Ed Khalturin
3 min readJul 13, 2019

--

Наш поиск будет:

  • Динамически обновляться по мере ввода текста
  • Способен индексировать любое кол-во полей в объекте (одно, два и более)
  • Подсвечивать совпадающие области
Что будет готово в итоге

Примечание: В этом проекте я использую Kotlin Anko, поэтому к View элементам обращаюсь напрямую без findViewById(). На конечный результат это никак не повлияет

0. Создаём обычный RecyclerView, адаптер и xml-разметки

На этом шаге ничего особенного не будет. Делайте так же, как и всегда раньше

RvAdapter.kt

MainActivity.kt

activity_main.xml

item.xml

1. Создаём объект, который будем отображать в RecyclerView

Расскажу, что тут происходит. Те поля, которые мы хотим подсветить в дальнейшем при поиске, описываем как Spannable. Если не хотим подсвечивать, то пишем просто String.

Для удобства я создал дополнительный конструктор, который принимает обычные String и сам преобразует их в Spannable, благо это делается в одну строчку

2. Обрабатываем поле поиска

В activity_main.xml имеется EditText “etSearchBar”. Повесим на него слушатель обновления текста

Вся магия будет проходить в методе updateSearch():

Самая важная строчка:

it.abbr.startsWith(s.toString(), true) || it.name.contains(s.toString(), true)

В ней мы вставляем условие, по которому будем фильтровать содержимое. В данном случае мы оставим объект, если его аббревиатура (поле abbr) начинается с нашего запроса, либо его полное название (поле name) содержит наш запрос.

3. ItemStorage

Класс ItemStorage для простоты будет содержать список с данными, заполненными вручную. Вы можете использовать в качестве источника базу данных или данные, полученные с сервера. Далее мы будем получать на основе этого списка отфильтрованные данные и передавать их в адаптер. Этот список не уменьшается по мере ввода пользователем своего запроса.

❗ В методе updateSearch() мы работаем с этим листом. Я его поместил в отдельный класс под названием ItemStorage

Создавать отдельный класс необязательно, главное иметь копию листа со всеми предметами

Поиск готов, можно использовать, однако, давайте его улучшим, сделав подсветку

4. Подсветка

4.1. Выбираем стиль подсветки

Помните про Spannable? Именно он будет менять форматирование текста. Добавим этот параметр в поле класса

Данный конструктор просто поменяет цвет текста на R.color.colorAccent

4.2. Подсвечиваем

В override fun onTextChanged() вызываем метод highlight(), который будет подсвечивать совпадения в наших View

Комментарии к коду:

{1} и {2} — удаляем выделение у текста, чтобы наша подсветка работала корректно, когда удаляем текст из поле поиска

{3} — добавляем подсветку в поле отображения abbr. Мы сделали выделение с 0 индекса по s.length, потому что ранее мы сделали индексацию этого поля, если строка поиска s является началом аббревиатуры abbr в документе

{4} — добавляем подсветку в поле отображения name. Тут уже допустимо совпадение подстроки в любом месте, даже в середине текста, поэтому проводим несложные вычисления по индексам-границам выделения

**item.abbr.setSpan(**
<как будет выделено>,
<с какого индекса>,
<по какой индекс>,
<включение/исключение первой/последней границы выделения>)

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE — включаем обе границы в диапазон выделения

Подробнее про Spannable можно почитать тут

Вы великолепны!

Посмотреть весь код можно здесь

--

--