- Create RecyclerView in Android Fragment
- Step 1: Create a Basic Activity Project
- Step 2: Create a RecyclerView resource
- Step 3: Create a FrameLayout with TextView
- Step 5: Create Recycler ViewHolder
- Step 6: Create RandomNumListAdapter
- Result: RecyclerView with a list of random numbers
- sheharyarn / RVFragment.java
- Android RecyclerView с использованием котлиновских sealed классов
- Почему sealed классы Kotlin?
- Создание sealed классов в Kotlin
- Создание адаптера RecyclerView
- DiffCallback
- RecyclerView
- Принцип работы
- Добавление RecyclerView в проект
- Библиотека
- Добавление в макет
- Макет элемента списка
- Адаптер и viewHolder
- Последние штрихи
- Создание RecyclerView с помощью шаблона
- Стандартные LayoutManager’ы
- LinearLayoutManager
- GridLayoutManager
- StaggeredGridLayoutManager
- Динамическое переключение
- SnapHelper
- Использование нескольких макетов для элементов RecyclerView
- ViewType
- Несколько списков в одном RecyclerView
- ConcatAdapter
- Использование ConcatAdapter . Обзор некоторых методов класса
- Пример с header’ом и footer’ом
- Полезные ссылки
Create RecyclerView in Android Fragment
Android Official Documentation provided a tutorial for creating a RecyclerView in Activity. However, it is a bit different when trying to create a RecyclerView in Fragment instead.
Step 1: Create a Basic Activity Project
Open Android Studio, Create new project -> select Basic Activity -> Finish Application creation. Once you run the app on emulator, you will see a single activity application with a button which allows you to switch between two fragments.
Step 2: Create a RecyclerView resource
We are going to create a RecyclerView resource in SecondFragment. Go to /res/layout/fragment_second.xml, add the following lines to create RecyclerView:
Alternatively, we can also use Palette in Android Studio to create RecyclerView:
- Drag RecyclerView from Palette to Layout in fragment_second.xml (using Design view).
- Define RecyclerView id as `recyclerview`.
- Since this is created under ConstraintLayout, define Constraint Widget in 4 directions under Layout.
Step 3: Create a FrameLayout with TextView
After creating RecyclerView, we need to define resource for each item (TextView) in RecyclerView. Create a new file under /res/layout/: frame_textview.xml:
Copy the following lines to this new file.
Alternatively, you can also use Palette to create TextView
- Drag TextView from Palette to Layout in frame_textview.xml (using Design view).
- Define TextView id as `randomText`
Step 4: Add RecyclerView in Fragment
Under recyclerview/SecondFragment.java, add the following lines to inject recyclerView to fragment. Note that ReyclerView needs to be retrieved by using the view.findViewById() instead findViewById() directly. view can retrieved from inflater.inflate().
Step 5: Create Recycler ViewHolder
Under recyclerview/, create RecyclerViewHolder.java, add the following lines to define how to create a ViewHolder. One ViewHolder contains necessary UI information about one item in RecyclerView. In this example, itemView is the FrameLayout component from step #3. We need to retrieve and store TextView randomText from FrameLayout .
Step 6: Create RandomNumListAdapter
Under recyclerview/, create RandomNumListAdapter.java, add the following lines to define how to adapter data to RecyclerView.
Here we want to show a list of Random numbers in RecyclerView, therefore we take a randomness seed as parameter in constructor.
In getItemViewType(), we will provide the layout file which contains the TextView for list item. In this example, this is frame_textview from Step #3 .
In onCreateViewHolder(), we take the viewType which is the returned by getItemViewType(). After inflating FrameLayout to get View object, we then can use RecyclerViewHolder created by Step #5 for return value.
In onBindViewHolder(), we will bind the RecyclerViewHolder to RecyclerView. In this example, we will generate a random number at runtime for this view item. Note that random number will be generated every time a ViewHolder is bind to RecyclerView, so we can implicitly know that if an item is unbind and bind again at the same position.
Result: RecyclerView with a list of random numbers
Now all the code changes are done, run the app again and click NEXT button on emulator. If you see a list of random numbers as below, congratulations! You have created a RecyclerView in this fragment!
If you scroll down the RecyclerView, you will see more random numbers. And if you scroll up, you will find that the numbers are different than the number at the same position before. That is because the view item out of screen will be automatically recycled and bind as another view item currently on the screen. Everytime an item is bind to RecyclerView, this app will generate a new random number and set to TextView.
Источник
sheharyarn / RVFragment.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
/** |
* RVFragment — Fragment with a simple RecyclerView that |
* only takes Strings |
* |
* Usage: |
* RVFragment rvf = new RVFragment(); |
* |
* @author Sheharyar Naseer |
*/ |
public class RVFragment extends Fragment < |
String [] strings = < " 1 " , " 2 " , " 3 " , " 4 " , " 5 " , " 6 " , " 7 " >; |
public RVFragment () <> |
@Override |
public View onCreateView ( LayoutInflater inflater , ViewGroup container , Bundle savedInstanceState ) < |
RecyclerView rv = new RecyclerView (getContext()); |
rv . setLayoutManager( new LinearLayoutManager (getContext())); |
rv . setAdapter( new SimpleRVAdapter (strings)); |
return rv; |
> |
/** |
* A Simple Adapter for the RecyclerView |
*/ |
public class SimpleRVAdapter extends RecyclerView . Adapter SimpleViewHolder > < |
private String [] dataSource; |
public SimpleRVAdapter ( String [] dataArgs ) < |
dataSource = dataArgs; |
> |
@Override |
public SimpleViewHolder onCreateViewHolder ( ViewGroup parent , int viewType ) < |
View view = new TextView (parent . getContext()); |
SimpleViewHolder viewHolder = new SimpleViewHolder (view); |
return viewHolder; |
> |
@Override |
public void onBindViewHolder ( SimpleViewHolder holder , int position ) < |
holder . textView . setText(dataSource[position]); |
> |
@Override |
public int getItemCount () < |
return dataSource . length; |
> |
> |
/** |
* A Simple ViewHolder for the RecyclerView |
*/ |
public static class SimpleViewHolder extends RecyclerView . ViewHolder < |
public TextView textView; |
public SimpleViewHolder ( View itemView ) < |
super (itemView); |
textView = ( TextView ) itemView; |
> |
> |
> |
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Источник
Android RecyclerView с использованием котлиновских sealed классов
RecyclerView — это один из самых лучших инструментов для отображения больших списков на Android. Как разработчики, вы, скорее всего понимаете о чем я говорю. У нас есть много дополнительных фич, таких как шаблоны вью холдеров, сложная анимация, Diff-Utils колбек для повышения производительности и т. д. Такие приложения, как WhatsApp и Gmail, используют RecyclerView для отображения бесконечного количества сообщений.
Одна из важнейших фич RecyclerView , которые я использую, — это типы представлений (view types). В RecyclerView мы можем отобразить несколько типов представлений. Раньше разработчики делали это с помощью флага типа представления в модели списка, который возвращали в функции getViewType адаптера RecyclerView .
Почему sealed классы Kotlin?
После появления Kotlin для разработки приложений под Android наши подходы к реализации кода кардинально изменились. То есть такие фичи, как расширения, почти заменили потребность в поддержании базовых классов для компонентов Android. Делегаты Kotlin внесли изменения в нашу работу с сеттерами и геттерами.
Теперь пришло время обновлений в работе адаптера RecyclerView . Sealed классы из Kotlin оказывают значительное влияние на управление состояниями. Подробнее прочитать об этом вы можете в этой статье.
Вдохновившись этой статьей, я хочу показать вам реализацию типов представлений в RecyclerView с использованием sealed классов. Мы постараемся развить сравнение случайных чисел или лейаутов до типов классов. Если вы фанат Kotlin, я уверен, что вам понравится эта реализация.
Создание sealed классов в Kotlin
Первое, что нам нужно сделать при этом подходе — это создать все классы данных, которые мы намерены использовать в адаптере, а затем необходимо связать их в sealed классе. Давайте создадим группу классов данных:
Это несколько классов данных, которые я хотел отобразить в списке, основываясь на данных с серверов. Вы можете создать столько классов данных, сколько захотите. Этот подход хорошо масштабируется.
То, что мы можем работать с состояниями загрузки, хедерами, футерами и многим другое без написания дополнительных классов — это одно из крутых преимуществ данного метода. Вы скоро узнаете, как это сделать. Следующим шагом является создание sealed классов, содержащих все необходимые классы данных:
Sealed класс с пользовательскими моделями
Как я упоминал ранее, мы можем без дополнительных сложностей добавлять хидеры и футеры из RecyclerView , используя объект Kotlin:
Sealed класс с хидером и футером
На этом этапе заканчивается реализация нашего sealed класса.
Создание адаптера RecyclerView
После того, как мы разобрались с sealed классом, пришло время создать адаптер RecyclerView с UIModel списком. Это простой RecyclerView , но с sealed классом arraylist :
В приведенном выше коде показана базовая реализация адаптера RecyclerView без какой-либо логики sealed классов. Как можно заметить, мы объявили sealed классы arraylist (UIModel). Следующим шагом является возврат соответствующего типа представления на основе позиции:
Сравнение модели sealed класса для получения типа представления
Теперь, когда мы успешно вернули правильный лейаут на основе модели sealed класса, нам нужно создать соответствующий ViewHolder в функции onCreateViewHolder на основе viewtype :
Создание вью холдера с учетом типа представления из sealed классов
Последний шаг — обновить вью холдер на основе текущих данных элемента, чтобы адаптер мог отображать данные в пользовательском интерфейсе. Поскольку у адаптера есть несколько представлений, мы должны классифицировать тип, а затем вызвать соответствующий ViewHolder :
После объединения всех частей кода, он выглядит так:
Финальная версия адаптера
На этом этапе мы закончили. Мы реализовали все необходимое. Вы можете создать инстанс адаптера в Activity/Fragment и присвоить его RecyclerView . Как только вы получите данные, вам нужно вызвать функцию submitData с ArrayList :
Публикация данных в адаптер RecyclerView
DiffCallback
«DiffUtil — это вспомогательный класс, который может вычислять разницу между двумя списками и выводить список операций обновления, который преобразует первый список во второй». — Android Developer
Реализация diffcallback не является обязательной, но она повысит производительность, если вы работаете с большими наборами данных. Итак, чтобы реализовать difCallback в нашем адаптере, нам нужно различать модели и сравнивать нужные переменные:
Она похожа на стандартную реализацию diffCallback , но нам необходимо разделять типы. Создав ее, свяжите ее с адаптером в конструкторе.
Это все. Надеюсь, эта статья была для вас полезной. Спасибо за внимание!
Всех желающих приглашаем на двухдневный онлайн-интенсив «Делаем мобильную мини-игру за 2 дня». За 2 дня вы сделаете мобильную версию PopIt на языке Kotlin. В приложении будет простая анимация, звук хлопка, вибрация, таймер как соревновательный элемент. Интенсив подойдет для тех, кто хочет попробовать себя в роли Android-разработчика.
>> РЕГИСТРАЦИЯ
Источник
RecyclerView
RecyclerView — компонент для отображения элементов списка, который является более продвинутой и гибкой версией ListView , но не является его родственником, а относится к семейству ViewGroup .
Принцип работы
Для отображения данных RecyclerView использует несколько компонентов:
- Объект RecyclerView , который нужно добавить в макет. Он заполняется элементами списка в зависимости от того, какой был установлен LayoutManager . Существуют стандартные LayoutManager ‘ы, например, LinearLayoutManager отображает элементы в виде списка, а GridLayoutManager — в виде сетки. Но можно создать и свой собственный LayoutManager .
- Элементы списка представлены в виде объектов viewHolder . Например, если список состоит из различных видов деревьев, то viewHolder — это конкретный вид дерева — сосна, яблоня, берёза и т.д. RecyclerView создает столько объектов viewHolder , сколько требуется для отображения на экране устройства и несколько про запас. Когда пользователь начинает прокручивать список, RecyclerView берёт те объекты viewHolder , которые ушли за пределы экрана и “привязывает” к ним новые данные.
- Объекты viewHolder управляются адаптером. Он создаёт объекты viewHolder и привязывает к ним информацию.
Добавление RecyclerView в проект
Библиотека
По умолчанию (при создании нового проекта) функциональность RecyclerView не доступна. Поэтому для начала нужно добавить соответствующую библиотеку. Для этого в файл build.gradle , который находится в папке app , добавьте одну из библиотек:
Версия support library уже вряд ли когда-нибудь изменится, так как её поддержку остановили. А вот за версией androidx нужно следить.
После того, как библиотека добавлена, обязательно нажмите на кнопку Sync Now, чтобы изменения вступили в силу.
Добавление в макет
Библиотека добавлена, а значит теперь мы можем обращаться к RecyclerView . Первым делом следует добавить его в макет. Он может быть добавлен как дочерний элемент другого компонента:
Либо может быть единственным (корневым) компонентом макета:
Далее для корректной работы RecyclerView требуется установить LayoutManager и адаптер. LayoutManager может быть установлен двумя способами. В макете:
Либо вместе с адаптером в классе фрагмента или активити:
При этом начиная с версии Android Studio 3.6 необязательно вызывать метод findViewById(), а можно напрямую обратится к компоненту из макета по его идентификатору (как в примере выше).
Макет элемента списка
Для элемента списка можно создать собственный макет. Например, у меня каждый элемент состоит из названия дерева и его краткого описания. Поэтому макет для элемента включает в себя два компонента TextView :
А можно воспользоваться стандартными макетами, к которым можно обращаться через android.R.layout.НАЗВАНИЕ_ИЗ_СПИСКА . Но на мой взгляд это вариант для ленивых или для любопытных.
Адаптер и viewHolder
Адаптер — это класс, который занимается передачей данных в список, созданием объектов viewHolder и их обновлением. Адаптер должен наследоваться от класса RecyclerView.Adapter .
ViewHolder — это тоже класс, объекты которого адаптер использует для хранения и визуализации элементов списка. ViewHolder должен наследоваться от класса RecyclerView.ViewHolder . Как правило этот класс располагают внутри адаптера.
В классе адаптера нужно обязательно переопределить 3 метода:
- onCreateViewHolder() — данный метод вызывается LayoutManager ‘ом, чтобы создать объекты viewHolder и передать им макет, по которому будут отображаться элементы списка.
- onBindViewHolder() — данный метод вызывается LayoutManager ‘ом, чтобы привязать к объекту viewHolder данные, которые он должен отображать.
- getItemCount() — возвращает общее количество элементов в списке.
А в классе ViewHolder требуется указать используемые компоненты разметки.
Последние штрихи
Теперь адаптер настроен и готов к использованию. Осталось только его подключить. Делается это в классе фрагмента или активити (в моём примере используется фрагмент).
Если какой-либо элемент списка изменился, то следует вызвать метод адаптера notifyItemChanged() и передать ему позицию элемента, которую требуется обновить. Вместо него можно использовать метод notifyDataSetChanged() , который будет обновлять полностью весь список, но из-за этого он является ресурсозатратным.
Создание RecyclerView с помощью шаблона
Есть возможность пропустить все вышеописанные шаги и воспользоваться стандартным шаблоном. Этот шаблон автоматически добавит в проект новый фрагмент с поддержкой RecyclerView . Это означает, что студия за вас создаст не только фрагмент, но и адаптер, ViewHolder , макет для элемента списка, а также код, который всё это подключает.
Кликните по любому файлу правой кнопкой мыши и в появившемся контекстном меню выберите: New > Fragment > Fragment (List).
Стандартные LayoutManager’ы
RecyclerView использует LayoutManager для того, чтобы расположить элементы списка на экране. При этом каждый LayoutManager позволяет расположить их по-своему.
Существует три стандартных LayoutManager ‘а:
- LinearLayoutManager — упорядочивает элементы в виде обычного вертикального или горизонтального списка.
- GridLayoutManager — размещает элементы в виде сетки одинакового размера.
- StaggeredGridLayoutManager — размещает элементы в виде неравномерной сетки: каждый столбец будет слегка смещён по сравнению с предыдущим.
Как правило этих вариантов достаточно для большинства ситуаций. Но если это не ваш случай, то можно создать свой собственный LayoutManager , расширив класс RecyclerView.LayoutManager .
LinearLayoutManager
По умолчанию LinearLayoutManager упорядочивает элементы в виде вертикального списка.
У данного класса есть другой конструктор, который позволяет явно задать ориентацию списка. Помимо контекста, ему требуется два параметра:
- Ориентация — задаётся с помощью констант HORIZONTAL и VERTICAL класса LinearLayoutManager .
- Булево значение: если передать true — список будет установлен в обратном порядке (начало будет в конце).
Эти параметры можно устанавливать с помощью специальных методов:
Либо с помощью специальных атрибутов в XML:
GridLayoutManager
Размещает элементы списка в виде сетки одинакового размера.
У класса GridLayoutManager есть два конструктора. Для использования первого конструктора необходимы два параметра: контекст и количество столбцов в сетке.
Для второго конструктора — четыре параметра:
- контекст;
- количество столбцов в сетке;
- ориентация списка — задаётся с помощью констант HORIZONTAL и VERTICAL класса LinearLayoutManager ;
- булево значение — если передать true — список будет установлен в обратном порядке (начало будет в конце).
Если задать горизонтальную ориентацию, то в списке будет столько рядов, сколько было задано вторым параметром (в данном примере = 3), а листаться, само собой, будет в бок.
То же самое можно задать с помощью XML атрибутов:
StaggeredGridLayoutManager
Размещает элементы в виде неравномерной сетки.
У класса StaggeredGridLayoutManager всего один конструктор с двумя параметрами:
- количество столбцов в сетке;
- ориентация списка — задаётся с помощью констант HORIZONTAL и VERTICAL класса StaggeredGridLayoutManager .
Если задать горизонтальную ориентацию, то в списке будет столько рядов, сколько было задано первым параметром (в данном примере = 3), а листаться, само собой, будет в бок.
То же самое можно задать с помощью XML атрибутов:
Динамическое переключение
Переключаться между LayoutManager ‘ами можно динамически. Например, при нажатии на кнопку:
SnapHelper
SnapHelper позволяет настроить “прилипание” элементов к определённой позиции в RecyclerView . Например, при пролистывании можно настроить прилипание таким образом, что первый видимый элемент будет сам прилипать к краю экрана или ближайший к центру элемент будет автоматически вставать в центр экрана.
Существует два стандартных класса для работы с прилипанием элементов: LinearSnapHelper и PagerSnapHelper .
LinearSnapHelper застовляет ближайший к центру элемент вставать в центр экрана. Допустим вы листаете список и в какой-то момент убрали пальцы от экрана. Список без вашего участия автоматически прокрутится и установит в центр экрана ближайший элемент.
PagerSnapHelper предназначен для полноэкранных элементов и ведёт себя как ViewPager .
Добавить себе в проект просто:
Если ни один вариант вас не устраивает, то создайте свою собственную реализацию этих классов и опишите в нёй необходимое поведение элементов при пролистывании списка.
Использование нескольких макетов для элементов RecyclerView
При отображении списка все его элементы выглядят одинаково и в большинстве случаев это оправдано и разработчика вполне устраивает. Тем не менее возникают ситуации, когда нужно один или целый ряд элементов выделять из остальных. Например:
- требуется добавить header или footer;
- отображение двух списков в одном RecyclerView ;
- выделение определённого элемента в списке.
ViewType
Одним из способов, который используется для выделения элементов в списке, является присвоение viewType каждому объекту viewHolder . ViewType — это произвольное цифровое значение от 0 и выше, которое необходимо для того, чтобы различать объекты viewHolder между собой. Например, если вам требуется добавить header и footer, при этом элементы списка должны выглядеть идентично, то у вас будет три viewType : для header’а, footer’а и элемента списка.
Для начала добавьте в папку res/layout три макета: для header’а, footer’а и элемента списка.
В классе адаптера создадим константы, которые будут хранить значения viewType .
Для удобства создадим базовый класс GenericViewHolder .
От него будут наследоваться три класса ViewHolder . Каждый из них отвечает за свой макет и привязку к нему данных.
Обратите внимание на класс ListItemViewHolder . В отличии от остальных он является внутренним (модификатор inner ), так как ему для привязки данных требуется обращаться к свойству trees своего внешнего класса. Из поступившего номера позиции вычитается единица, так как нулевая позиция занята header’ом и не будет сюда поступать.
Теперь возьмёмся за код самого адаптера. С помощью метода getItemViewType() зададим viewType каждому объекту viewHolder в зависимости от его позиции в списке. Первый и последний элемент списка — это header и footer. Если в списке 15 элементов, то позиция для footer’а будет 15 + 1, так как header всегда находится в нулевой позиции.
В методе onCreateViewHolder() создаём объект viewHolder в зависимости от viewType .
В методе onBindViewHolder() вызываем метод привязки данных bindView() , который переопределён во всех наших классах ViewHolder .
Метод getItemCount() должен возвращать количество элементов в RecyclerView . Поэтому следует учесть наличие header’а и footer’а.
Адаптер готов к использованию. Результат будет примерно таким:
Несколько списков в одном RecyclerView
У меня как-то возникала необходимость отображения двух списков на одном экране друг за другом. При этом при клике по элементу из первого списка он должен был переместиться во второй список и наоборот.
Первая появившаяся мысль — добавить на экран два RecyclerView . И это вполне себе работает. Но возникает ряд неудобств, одно из них — некорректная работа overScroll. Эффект overScroll визуально показывает, что вы дошли до конца или начала списка.
И если на экране два RecyclerView , то эффект overScroll появляется для каждого из них. Выглядит не очень красиво. Конечно можно overScroll эффект отключить, но тогда появляется неуверенность: “А дошел ли я до конца списка?”.
В общем нашлось решение, при котором один RecyclerView работает с двумя списками и завязано это всё на использовании viewType из примера выше.
Создаём два макета — один для элементов первого списка, второй — для элементов второго списка. У меня они отличаются только цветом фона — у элементов первого списка он белый, у второго — красный.
Константы для хранения значений viewType :
Также используем для удобства базовый класс GenericViewHolder .
От него будут наследоваться два класса ViewHolder : один для элементов первого списка, второй для элементов второго списка.
Каждый из них будет по своему реализовывать метод bindView() . Для элементов первого списка ничего рассчитывать не требуется, нужно просто привязать к объектам viewHolder данные по порядку.
Второй список должен отображаться сразу после первого. Так как номер позиции может быть любым числом от 0 до list1.size + list2.size , в методе bindView() класса SecondListItemViewHolder потребуется произвести расчеты.
Также обратите внимание что оба класса являются внутренними (модификатор inner ), так как им для привязки данных требуется обращаться к компонентам адаптера list1 и list2 .
Переходим к коду адаптера. В методе getItemViewType() нужно предусмотреть все возможные сценарии: когда в обоих списках есть элементы и когда в одном из списков нет элементов.
В методе onCreateViewHolder() создаём объект viewHolder в зависимости от viewType .
В методе onBindViewHolder() вызываем метод привязки данных bindView() , который переопределён во всех наших классах ViewHolder , а также вешаем слушателя.
Метод getItemCount() должен возвращать количество элементов в RecyclerView . Поэтому следует учесть наличие двух списков.
При клике по элементу из первого или второго списка будет вызван метод updateUi() , который отмечает, что по элементу кликнули и переносит его в другой список.
Адаптер готов к использованию. Результат будет примерно таким:
Необязательно делать списки динамическими, таким образом можно отображать и статические списки. И даже комбинировать с предыдущим примером — добавлять header (один или для всех списков) и footer.
ConcatAdapter
Несмотря на то, что все примеры, описанные в предыдущем разделе, вполне себе рабочие, в плане кода выглядят не очень хорошо. В основном из-за того, что в одном адаптере скапливается множество реализаций класса ViewHolder , а также логика их отображения. Если нам понадобится добавить или удалить какой-либо ViewHolder , то придётся переписывать класс адаптера и заново его тестировать.
По этой причине в recyclerview:1.2.0-alpha02 был добавлен новый класс MergeAdapter , который в версии recyclerview:1.2.0-alpha04 переименовали в ConcatAdapter .
ConcatAdapter позволяет отображать содержимое нескольких адаптеров в одном RecyclerView . То есть вместо накапливания множества реализаций класса ViewHolder в одном адаптере, мы можем создать для каждого ViewHolder ‘а свой адаптер, а потом объединить их все при помощи ConcatAdapter . Таким образом код станет более понятным и переиспользуемым, а если потребуется добавить в RecyclerView что-то новое — просто создадим новый адаптер.
Использование ConcatAdapter . Обзор некоторых методов класса
Передайте в конструктор ConcatAdapter все ваши адаптеры, которые нужно объединить, чтобы отображать их в одном RecyclerView .
Адаптеры будут отображаться на экране в том порядке, в котором были переданы в конструктор класса ConcatAdapter .
Если один из адаптеров должен несколько раз отображаться на экране, то создайте несколько объектов этого адаптера и передайте их все в конструктор класса ConcatAdapter .
Когда мы вызываем метод notifyDataSetChanged() в любом из адаптеров, ConcatAdapter тоже его вызывает.
У класса ConcatAdapter есть конструктор, который позволяет передавать список из адаптеров. На экране они будут отображаться в том порядке, в котором были добавлены в список.
Если вам нужно добавить один из адаптеров не сразу, а позже, то используйте метод addAdapter() . Этот метод добавляет адаптер в последнюю позицию, т.е. отображаться он будет после всех остальных.
Если же требуется добавить адаптер не последним, а в определённую позицию, то в метод addAdapter() передайте номер позиции и сам адаптер. Метод добавит адаптер в указанную позицию, а все остальные адаптеры сместятся.
Обратите внимание, что номер позиции не может быть больше количества адаптеров (отсчёт начинается с нуля). В примере у нас три адаптера, каждому из которых может быть присвоена позиция 0, 1 или 2. Если указать число выше, то вылетит ошибка.
Для удаления адаптера используется метод removeAdapter() .
Чтобы узнать сколько элементов объединил в себе ConcatAdapter вызовите метод itemCount . Количество элементов суммируется со всех добавленных адаптеров.
Можно получить список всех адаптеров, добавленных в ConcatAdapter . Для этого вызовите adapters , который возвращает MutableList со всеми адаптерами.
Обычно если в адаптере нам надо обратиться к какой-либо позиции, мы используем метод getAdapterPosition() класса ViewHolder . При работе с ConcatAdapter вместо getAdapterPosition() следует использовать getBindingAdapterPosition() .
Пример с header’ом и footer’ом
Возьмём пример, который был в разделе ViewType: требуется отобразить header, footer и список между ними. В таком случае у нас будет три адаптера: для header’а, footer’а и элементов списка. Можно использовать и два адаптера, если логика и внешний вид header’а и footer’а идентичны. Но для наглядности в своём примере я буду использовать три.
Для начала убедитесь, что в build.gradle добавлена нужная версия библиотеки recyclerView:
Можно использовать и версию 1.2.0-alpha02 , но учтите, что в этой версии ConcatAdapter ещё носит название MergeAdapter .
Создадим классы данных для header’а, footer’а и элементов списка (деревья).
Добавим макет для каждого компонента.
За отображение header’а будет отвечать HeaderAdapter .
Для отображения элементов списка создадим ListItemAdapter .
Ну и наконец адаптер для отображения footer’а.
Теперь осталось лишь объединить всё вместе в методе onCreate() — для активити или в методе onViewCreated() — для фрагмента. Для этого создадим по одному объекту каждого из адаптеров и передадим их классу ConcatAdapter() в том порядке, в котором они должны быть отражены на экране.
Если же в ConcatAdapter() передать footer сразу после header’а
то результат будет таким:
Полезные ссылки
Общие ссылки по теме:
Create a List with RecyclerView — гайд из официальной документации.
RecyclerView — документация по классу (androidx).
Recyclerview — Release Notes — информация о выходе новых версий.
Using the RecyclerView — гайд от codepath.
Кастомизация:
Having multiple lists in a single RecyclerView — гайд по использованию нескольких списков в одном RecyclerView .
Адаптеры:
ConcatAdapter — официальная документация.
Код:
RecyclerView — полный код всех примеров из данной статьи.
MergeAdapter-sample — пример реализации ConcatAdapter от Kotlin Android Open Source.
Concat Adapter Android Example — пример реализации ConcatAdapter от Mindorks.
Источник