- RecyclerView
- getItemCount()
- onCreateViewHolder
- onBindViewHolder()
- Горизонтальная прокрутка
- Оптимизация
- Пример использования CardView и RecyclerView в Android
- Предпосылки
- 1. Поддержка Старых Версий
- 2. Создание CardView
- 3. Создание RecyclerView
- Шаг 1: Определение RecyclerView в Layout
- Шаг 2: используйте LayoutManager
- Шаг 3: определение данных
- Шаг 4: создание адаптера
- Очень удобный абстрактный адаптер для RecyclerView своими руками
- А что вообще собственно нужно?
- Приступаем
- RecyclerBindableAdapter
- FilterBindableAdapter
- ParallaxBindableAdapter
- SimpleBindableAdapter
RecyclerView
Компонент RecyclerView появился в Android 5.0 Lollipop и находится в разделе Containers. Для простоты буду называть его списком, хотя на самом деле это универсальный элемент управления с большими возможностями.
Раньше для отображения прокручиваемого списка использовался ListView. Со временем у него обнаружилось множество недостатков, которые было трудно исправить. Тогда решили создать новый элемент с нуля.
Вначале это был сырой продукт, потом его доработали. На данном этапе можно считать, что он стал полноценной заменой устаревшего ListView.
Схематично работу RecyclerView можно представить следующим образом. На экране отображаются видимые элементы списка. Когда при прокрутке списка верхний элемент уходит за пределы экрана и становится невидимым, его содержимое очищается. При этом сам «чистый» элемент помещается вниз экрана и заполняется новыми данными, иными словами переиспользуется, отсюда название Recycle.
Компонент RecyclerView не является родственником ListView и относится к семейству ViewGroup. Он часто используется как замена ListView, но его возможности шире.
Следует сказать, что при работе с ним приходится писать много кода, который пугает новичков. Если с RecyclerView работать не постоянно, то порой забываются детали и сложно вспомнить необходимые шаги. Многие просто сохраняют отдельные шаблоны и копируют в разные проекты.
Внешний вид можно представить не только в виде обычного списка, но и в виде сетки. При необходимости можно быстро переключиться между разными типами отображения.
Для размещения своих дочерних элементов используется специальный менеджер макетов LayoutManager. Он может быть трёх видов.
- LinearLayoutManager — дочерние элементы размещаются вертикально (как в ListView) или горизонтально
- GridLayoutManager — дочерние элементы размещаются в сетке, как в GridView
- StaggeredGridLayoutManager — неравномерная сетка
Можно создать собственный менеджер на основе RecyclerView.LayoutManager.
RecyclerView.ItemDecoration позволяет работать с дочерними элементами: отступы, внешний вид.
ItemAnimator — отвечает за анимацию элементов при добавлении, удалении и других операций.
RecyclerView.Adapter связывает данные с компонентом и отслеживает изменения.
- notifyItemInserted(), notifyItemRemoved(), notifyItemChanged() — методы, отслеживающие добавление, удаление или изменение позиции одного элемента
- notifyItemRangeInserted(), notifyItemRangeRemoved(), notifyItemRangeChanged() — методы, отслеживающие изменение порядка элеметов
Стандартный метод notifyDataSetChanged() поддерживается, но он не приводит к внешнему изменению элементов на экране.
Программисты со стажем знают, что для создания «правильного» ListView нужно было создавать класс ViewHolder. В старых списках его можно было игнорировать. Теперь это стало необходимым условием.
Общая модель работы компонента.
Мы рассмотрим только базовый пример для быстрого знакомства. В реальных проектах примеры будут гораздо сложнее, чтобы обеспечить другие функциональные возможности — обработка жестов, анимация, динамическое удаление и добавление элементов.
Размещаем компонент в макете экрана через панель инструментов. Но сначала добавим зависимость.
Создадим макет для отдельного элемента списка. Варианты могут быть самыми разными — можно использовать один TextView для отображения строк (имена котов), можно использовать связку ImageView и TextView (имена котов и их наглые морды). Мы возьмём для примера две текстовые метки. Создадим новый файл res/layout/recyclerview_item.xml.
Добавим компонент в разметку экрана активности.
Минимальный код для запуска.
Пока ничего сложного, но выводить такой список ничего не будет. Нужен адаптер и данные для отображения. В адаптере описывается способ связи между данными и компонентом.
Начнём по порядку, чтобы запомнить последовательность. Для начала создадим обычный класс и в конструкторе передадим список строк. Список будет содержать имена котов.
Класс MyViewHolder на основе ViewHolder служит для оптимизации ресурсов. Новый класс добавим в состав нашего созданного ранее класса.
В созданном классе нужно просто перечислить используемые компоненты из макета для отдельного элемента списка. В нашем примере задействованы два TextView, инициализируем их через идентификаторы.
Создадим адаптер — наследуем наш класс от класса RecyclerView.Adapter и в качестве параметра указываем созданный нами MyViewHolder. Студия попросит реализовать три метода.
getItemCount()
Как правило данные являются однотипными, например, список или массив строк. Адаптеру нужно знать, сколько элементов нужно предоставить компоненту, чтобы распределить ресурсы и подготовиться к отображению на экране. При работе с коллекциями или массивом мы можем просто вычислить его длину и передать это значение методу адаптера getItemCount(). В простых случаях мы можем записать код в одну строчку.
onCreateViewHolder
В методе onCreateViewHolder нужно указать идентификатор макета для отдельного элемента списка, созданный нами ранее в файле recyclerview_item.xml. А также вернуть наш объект класса ViewHolder.
onBindViewHolder()
В методе адаптера onBindViewHolder() связываем используемые текстовые метки с данными — в одном случае это значения из списка, во втором используется одна и та же строка.
Должно получиться следующее.
Подключаем в активности. Создадим пока бессмысленный список строк, который передадим в адаптер.
Запускаем ещё раз.
Вариант с числами нам не интересен, поэтому добавим котов. Имена котов и кошек разместим в ресурсах в виде массива в файле res/values/strings.xml.
Создадим новую функцию для получения списка котов из ресурсов и передадим его адаптеру.
Горизонтальная прокрутка
Можем указать горизонтальный вариант прокрутки. Остальной код менять не придётся.
А можно вообще обойтись только XML-декларацией.
Оптимизация
При прокрутке под капотом выполняется сложная работа по обновлению контента. Поэтому не следует перегружать элементы списка сложной структурой и не перебарщивайте с вложенными элементами, а также нужно следить за оптимизацией, чтобы избежать лагов.
При работе с изображениями старайтесь использовать готовые библиотеки Picasso, Glide, Fresco и т.д.
Если картинки загружаются с сервера, неплохо заранее вычислять их размеры и пропорции. В некоторых случаях желательно позаботиться, чтобы картинки были одного размера (если это возможно).
Не перегружайте лишним кодом метод onBindViewHolder(). Только самое необходимое.
Источник
Пример использования CardView и RecyclerView в Android
В Android, начиная с версии 5.0 Lolipop, доступны новые View-элементы экрана, которые упрощают работу со списками: RecyclerView и CardView. С помощью этих компонентов ваше приложение будет выглядеть и вести себя в соответствии с рекомендациями спецификации Google Material Design.
Предпосылки
Убедитесь, что вы используете последнюю версию Android Studio. Вы можете скачать ее на официальном сайте Android.
1. Поддержка Старых Версий
На момент написания статьи, около 5% Android-устройств работают под управлением Android Lolipop. Однако, наблюдается стремительный рост, а благодаря библиотеке поддержки v7:21, вы можете использовать RecyclerView и CardView на устройства под управлением более старых версий Android.
Для этого добавьте следующие строки в раздел dependencies в файл сборки проекта build.gradle:
2. Создание CardView
В CardView является ViewGroup. Как и с любой другой ViewGroup, с CardView можно взаимодействовать в Activity или Fragments, используя XML-файл макета.
Чтобы создать CardView, вам нужно будет добавить следующий код в ваш макет XML, как показано в следующем фрагменте:
В нашем конкретном примере нужно создать макет LinearLayout, с CardView внутри. В свою очередь, CardView будет содержать:
- TextView для отображения имени
- TextView для отображения возраста
- ImageView для отображения фото
XML-код макета будет выглядеть так:
Вот так наполненный данными макет будет выглядеть на экране:
3. Создание RecyclerView
Шаг 1: Определение RecyclerView в Layout
Определяем RecyclerView в макете следующим образом:
Для получения ссылки на него в вашей activity, используйте следующий фрагмент кода:
Если вы уверены, что размер RecyclerView не будет изменяться, вы можете добавить этот код для улучшения производительности:
Шаг 2: используйте LayoutManager
В отличие от ListView, RecyclerView необходим менеджер компоновки для управления позиционированием своих элементов. Можно определить свой собственный LayoutManager , расширяя класс RecyclerView.LayoutManager. Однако в большинстве случаев, вы могли бы просто использовать один из стандартных подклассов LayoutManager :
- LinearLayoutManager
- GridLayoutManager
- StaggeredGridLayoutManager
В этом уроке я буду использовать LinearLayoutManager. По умолчанию он обеспечивает вид RecyclerView аналогично ListView.
Шаг 3: определение данных
Аналогично ListView, в RecyclerView нужен адаптер для доступа к его данным. Но прежде чем мы создадим адаптер, давайте создадим данные, доступные для работы. Напишем простой класс Person, представляющий человека и создадим метод для инициализации списка:
Шаг 4: создание адаптера
Чтобы создать адаптер для RecyclerView, наследуемся от RecyclerView.Adapter. Этот адаптер представляет шаблон проектирования viewholder, подразумевающий использование пользовательского класса, который расширяет RecyclerView.ViewHolder. Эта паттерн сводит к минимуму количество обращений к дорогостоящему в плане ресурсов методу findViewById.
Ранее в этом уроке, мы уже определили XML-файл макета для CardView, представляющего человека. Мы собираемся использовать этот макет сейчас. Внутри конструктора нашего кастомного ViewHolder, инициализируем View, входящие в RecyclerView.
Источник
Очень удобный абстрактный адаптер для RecyclerView своими руками
Когда-то, на заре моей карьеры Android-разработчиком, я просматривал примеры уже имеющихся приложений и в прекрасном, словно солнышко весной, U2020 я нашел пример очень удобного адаптера. Имя его BindableAdapter. Долгое время я использовал его как основу своих адаптеров для ListView и GridView, но их эра приходит к своему закату и наступает эра RecyclerView. Этой эре нужен новый удобный адаптер, и я попытался его сделать.
Для начала я решил спросить у Google «Где ж моя любимая?» «RecyclerBindableAdapter», и ответа он мне не дал. Я честно попытался найти адаптер, с которым мне было бы удобно работать, но все было тщетно. Все найденные мной примеры реализовывали лишь конкретный функционал и не старались быть абстрактными. Да и, честно говоря, многие моменты в них меня смущали, к примеру: во многих из них в конструктор зачем-то передавались Context и LayoutManager. Хотя у RecyclerView.Adapter есть прекрасный метод onAttachedToRecyclerView(RecyclerView recyclerView), а из полученного recyclerView можно без лишнего шума и пыли получить и Context и LayoutManager.
Все это наводило меня на мысли, что они написаны скорее на скорую руку, чем вдумчиво. Так как RecyclerView использую повсеместно и каждый раз плодить кучу похожего кода как-то не комильфо, то я решил исправить ситуацию и написать удобный абстрактный адаптер.
А что вообще собственно нужно?
Портировать тот самый BindableAdapter под RecyclerView, при этом постараться максимально использовать все новые возможности RecyclerView. Как всегда есть одно «но»: RecyclerView по умолчанию не имеет Header’ов и Footer’ов. Следовательно когда будущий пользователь постарается исправить эту проблему создав новый тип элемента, из-за этого номер позиции сместится на количество Header’ов. Это плохо. Значит нужно заранее сделать возможность работы с Header’ами и Footer’ами, а также предусмотреть их наличие в методах работы с данными.
Потом я подумал, что неплохо бы было реализовать и другие возможности RecyclerView которыми я часто пользуюсь, а именно: фильтрация элементов и параллакс Header’а. Тут тоже не все так гладко.
Адаптер предусматривающий фильтрацию вынужден хранить два списка объектов (общий список и список тех элементов, что сейчас отображаются). Следовательно он занимает больше памяти, да и методы для работы с элементами будут работать медленнее. Незачем заранее забивать память лишними данными, да и фильтрация нужна не так уж часто. Поэтому было принято решение сделать его отдельным классом расширяющим наш основной адаптер. Таким образом мы будем использовать этот адаптер только тогда, когда нам необходима фильтрация, а в остальных случаях будем использовать основной адаптер.
Похожая ситуация сложилась и с параллаксом Header’a. Основной адаптер может иметь множество Header’ов и Footer’ов. Реализовать параллакс сразу нескольких элементов синхронно скорее всего будет проблематично, да и выглядеть будет некрасиво, так что не смысла даже пытаться. Делаем его так же отдельным классом.
На этом этапе я подумал, что неплохо было бы иметь некий аналог SimpleAdapter. Такой, чтоб его можно было объявить одной строкой, просто подсунув в него Layout ID и ViewHolder. Ведь зачем плодить кучу кода для простого списка.
В итоге задача сводилась к созданию 4 адаптеров:
- RecyclerBindableAdapter — наш основной адаптер
- FilterBindableAdapter — адаптер с возможностью фильтрации
- ParallaxBindableAdapter — адаптер с возможностью параллакса Header’а
- SimpleBindableAdapter — простой адаптер
Приступаем
RecyclerBindableAdapter
Для начала сделаем возможным добавление Header’ов и Footer’ов, подобную реализацию я когда-то встретил на просторах StackOverflow и подкорректировал по нужды нашего адаптера. Я думаю подобную реализацию видели или делали большинство людей работающих с Android, поэтому подробно останавливаться на ней не буду.
Теперь нужно сделать методы для работы с данными, названия для них возьмем из BindableAdapter для ListView/GridView.
Ну вот в принципе мы и закончили наш RecyclerBindableAdapter. Полный текст можно посмотреть тут или под спойлером.
Теперь создадим какой-нибудь пример:
Вот так вот, все теперь просто. Работа с адаптером упростилась в разы. Здесь вы можете найти этот пример, а вот здесь пример для нескольких типов.
FilterBindableAdapter
Давайте теперь создадим адаптер с возможностью фильтрации. Расширяем RecyclerBindableAdapter и первым делом создаем два списка объектов: все объекты и те, что сейчас отображены. Переопределим часть методов, что бы теперь они работали с двумя списками.
Теперь сделаем фильтрацию.
Пример адаптера полностью аналогичен примеру RecyclerBindableAdapter за исключением одного метода. Этот метод для конвертации элемента в строку, что бы мы потом могли отфильтровать элементы.
Полный текст можно посмотреть тут или под спойлером.
Пример можно посмотреть тут.
ParallaxBindableAdapter
Теперь приступим к созданию эффекта параллакса. Изначально я планировал сделать параллакс только для Header’а, но потом подумал, что сделать параллакс и для Footer’а будет весьма интересным опытом. Для начала переопределим методы для добавления Header’ов и Footer’ов так, чтобы наш адаптер мог иметь только по одному их экземпляру.
Теперь давайте сделаем методы для сдвигания контейнера при скролле. Для этого в методе onAttachedToRecyclerView() повесим на RecyclerView OnScrollListener. Внутри него будем вызывать метод для сдвигания. Ну и естественно нужно создать методы для того, чтобы включать/отключать эффект параллакса.
Полный текст можно посмотреть тут или под спойлером.
Пример по сути точно такой же как и для RecyclerBindableAdapter, просто нужно изменить что расширять. Пример смотреть тут.
SimpleBindableAdapter
Для того, чтобы сделать такой адаптер, для начала нам понадобится создать свой ViewHolder. Это делается для того, что бы мы затем точно знали какие методы нам вызывать. Так же нужно сделать свой интерфейс от которого мы в дальнейшем будем наследоваться.
Теперь приступим к созданию нашего адаптера. Просто окончательно переопределим все методы из RecyclerBindableAdapter и будет создавать новый экземпляр нашего ViewHolder через Java Reflection.
Теперь о том, как им пользоваться. Все очень и очень просто.
Вот и все, очень просто, не правда ли. Конечно нам еще нужен ViewHolder.
Вот и вся инициализация. Вот здесь можно найти пример.
Вот ссылка на репозиторий, в нем вы найдете все примеры и адаптеры, а также больше документации на кривом английском.
PS. Проект еще не завершен на все 100% поэтому буду признателен за помощь, конструктивную критику и предложения по улучшению. Так же возможно к тому моменту когда вы прочтете эту статью, появится что-то новое.
PSS. На одном из проектов в которых я участвовал, мой коллега начал создание BindableAdapter для RecyclerView, но так и не закончил, сделав реализацию лишь под конкретный проект. В любом случае, если ты это читаешь, большее спасибо за толчок и за идею.
Источник