Как создать вложенный RecyclerView в Android
Вложенный RecyclerView - это реализация RecyclerView в RecyclerView. Пример такого макета можно увидеть в различных приложениях, таких как Play store, где внешний (родительский) RecyclerView имеет вертикальную ориентацию, тогда как внутренние (дочерние) RecyclerView имеют горизонтальную ориентацию. Подобный макет разработан здесь.
Подход:
Шаг 1. Добавьте необходимые зависимости
Добавьте следующие зависимости в файл build.gradle (: app). Первая зависимость, соответствующая RecyclerView, является обязательной, а вторая - для CardView, поэтому она не является обязательной в зависимости от требований пользовательского интерфейса. Поскольку здесь CardView используется в дочернем макете RecyclerView, поэтому добавляется зависимость CardView.
Примечание. После добавления зависимостей нажмите « Синхронизировать сейчас».
implementation ‘androidx.recyclerview:recyclerview:1.0.0’
implementation ‘androidx.cardview:cardview:1.0.0’
Примечание. Для правильных версий зависимостей проверьте здесь.
Шаг 2. Реализуйте родительский RecyclerView
Родительский RecyclerView реализован в файле activity_main. Здесь файл activity_main содержит только родительский RecyclerView, но его можно настроить в соответствии с требованиями.
activity_main
<? xml version = "1.0" encoding = "utf-8" ?> < androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent" android:layout_height = "match_parent" tools:context = ".MainActivity" > <!-- This is the parent RecyclerView--> < androidx.recyclerview.widget.RecyclerView android:id = "@+id/parent_recyclerview" android:layout_width = "wrap_content" android:layout_height = "wrap_content" app:layout_constraintBottom_toBottomOf = "parent" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintHorizontal_bias = "0.498" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toTopOf = "parent" app:layout_constraintVertical_bias = "0.271" /> </ androidx.constraintlayout.widget.ConstraintLayout > |
Шаг 3. Создайте макет элемента для родительского RecyclerView
Определите требования для родительского макета и добавьте соответствующие им представления в XML-файле макета. Здесь файлы макета называются parent_item . В дополнение к дочернему RecyclerView включен TextView для заголовка.
parent_item
<? xml version = "1.0" encoding = "utf-8" ?> android:orientation = "vertical" android:layout_width = "wrap_content" android:layout_height = "wrap_content" > <!--Title--> < TextView android:id = "@+id/parent_item_title" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:padding = "12sp" android:textSize = "18sp" /> < LinearLayout android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_margin = "12dp" android:orientation = "horizontal" > <!--Child RecyclerView--> < androidx.recyclerview.widget.RecyclerView android:id = "@+id/child_recyclerview" android:layout_width = "wrap_content" android:layout_height = "wrap_content" /> </ LinearLayout > </ LinearLayout > |
Шаг 4. Создайте макет элемента для дочернего RecyclerView
Макет элементов дочернего RecyclerView создается в XML-файле макета с именем child_item . Дочерний RecyclerView включает ImageView и TextView, оба заключены в CardView.
Следующее изображение используется в качестве ресурса ImageView, таким образом , он будет добавлен в папку растяжимой Resouce.

значок
child_item
<? xml version = "1.0" encoding = "utf-8" ?> < FrameLayout android:layout_width = "wrap_content" android:layout_height = "wrap_content" > <!--CardView that holds the elements of the child RecyclerView --> < androidx.cardview.widget.CardView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_margin = "12dp" > < RelativeLayout android:layout_width = "wrap_content" android:layout_height = "wrap_content" > <!--Image in the CardView--> <!--Here we have already given the source for the ImageView and we will not assign it in the Java code--> <!--So all the ImageViews will hold the same image--> < ImageView android:id = "@+id/img_child_item" android:layout_width = "100dp" android:layout_height = "100dp" android:layout_marginStart = "5dp" android:background = "@color/colorPrimaryDark" android:src = "@drawable/icon" /> < LinearLayout android:layout_width = "wrap_content" android:layout_height = "60dp" android:layout_toEndOf = "@id/img_child_item" android:padding = "12dp" android:layout_below = "@+id/img_child_item" android:layout_alignParentStart = "true" android:orientation = "vertical" > <!--Text in the CardView--> < TextView android:id = "@+id/child_item_title" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:textStyle = "bold" /> </ LinearLayout > </ RelativeLayout > </ androidx.cardview.widget.CardView > </ FrameLayout > |
Шаг 5: Создайте классы элементов для каждого из RecyclerViews.
Для каждого RecyclerView требуется класс Java, в котором конструктор инициализирует параметры элемента и объявляются методы получения и установки. Таким образом, создайте следующие классы Java:
- ChildItem: этот класс будет реализовывать методы конструктора, получателя и установщика для представлений макета child_item, которые мы хотим установить динамически.
- ParentItem: этот класс будет реализовывать методы конструктора, получателя и установщика для представлений макета parent_item, которые мы хотим установить динамически.
ChildItem
package com.example.nestedrecyclerview; public class ChildItem { // Declaration of the variable private String ChildItemTitle; // Constructor of the class // to initialize the variable* public ChildItem(String childItemTitle) { this .ChildItemTitle = childItemTitle; } // Getter and Setter method // for the parameter public String getChildItemTitle() { return ChildItemTitle; } public void setChildItemTitle( String childItemTitle) { ChildItemTitle = childItemTitle; } } |
ParentItem
package com.example.nestedrecyclerview; import java.util.List; public class ParentItem { // Declaration of the variables private String ParentItemTitle; private List<ChildItem> ChildItemList; // Constructor of the class // to initialize the variables public ParentItem( String ParentItemTitle, List<ChildItem> ChildItemList) { this .ParentItemTitle = ParentItemTitle; this .ChildItemList = ChildItemList; } // Getter and Setter methods // for each parameter public String getParentItemTitle() { return ParentItemTitle; } public void setParentItemTitle( String parentItemTitle) { ParentItemTitle = parentItemTitle; } public List<ChildItem> getChildItemList() { return ChildItemList; } public void setChildItemList( List<ChildItem> childItemList) { ChildItemList = childItemList; } } |
Шаг 6: Создайте класс адаптера для каждого из RecyclerViews.
Класс адаптера требуется для передачи данных, которые должны отображаться в представлениях RecyclerView.
Класс адаптера необходим как для классов ChildItem, так и для классов ParentItem.
- ChildAdapter: это класс адаптера для хранения информации, которая должна отображаться в представлениях класса ChildItem.
- ParentAdapter: это класс адаптера для хранения информации, которая должна отображаться в представлениях класса ParentItem.
В классе ParentItemAdapter создается экземпляр класса
RecyclerView.RecycledViewPool
Этот класс используется для передачи представлений между родительским RecyclerView и дочерним RecyclerView.
ChildItemAdapter
package com.example.nestedrecyclerview; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.List; public class ChildItemAdapter extends RecyclerView .Adapter<ChildItemAdapter.ChildViewHolder> { private List<ChildItem> ChildItemList; // Constuctor ChildItemAdapter(List<ChildItem> childItemList) { this .ChildItemList = childItemList; } @NonNull @Override public ChildViewHolder onCreateViewHolder( @NonNull ViewGroup viewGroup, int i) { // Here we inflate the corresponding // layout of the child item View view = LayoutInflater .from(viewGroup.getContext()) .inflate( R.layout.child_item, viewGroup, false ); return new ChildViewHolder(view); } @Override public void onBindViewHolder( @NonNull ChildViewHolder childViewHolder, position) int { // Create an instance of the ChildItem // class for the given position ChildItem childItem = ChildItemList.get(position); // For the created instance, set title. // No need to set the image for // the ImageViews because we have // provided the source for the images // in the layout file itself childViewHolder .ChildItemTitle .setText(childItem.getChildItemTitle()); } @Override public int getItemCount() { // This method returns the number // of items we have added // in the ChildItemList // ie the number of instances // of the ChildItemList // that have been created return ChildItemList.size(); } // This class is to initialize // the Views present // in the child RecyclerView class ChildViewHolder extends RecyclerView.ViewHolder { TextView ChildItemTitle; ChildViewHolder(View itemView) { super (itemView); ChildItemTitle = itemView.findViewById( R.id.child_item_title); } } } |
ParentItemAdapter
package com.example.nestedrecyclerview; import androidx.annotation.NonNull; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.List; public class ParentItemAdapter extends RecyclerView .Adapter<ParentItemAdapter.ParentViewHolder> { // An object of RecyclerView.RecycledViewPool // is created to share the Views // between the child and // the parent RecyclerViews private RecyclerView.RecycledViewPool viewPool = new RecyclerView .RecycledViewPool(); private List<ParentItem> itemList; ParentItemAdapter(List<ParentItem> itemList) { this .itemList = itemList; } @NonNull @Override public ParentViewHolder onCreateViewHolder( @NonNull ViewGroup viewGroup, int i) { // Here we inflate the corresponding // layout of the parent item View view = LayoutInflater .from(viewGroup.getContext()) .inflate( R.layout.parent_item, viewGroup, false ); return new ParentViewHolder(view); } @Override public void onBindViewHolder( @NonNull ParentViewHolder parentViewHolder, position) int { // Create an instance of the ParentItem // class for the given position ParentItem parentItem = itemList.get(position); // For the created instance, // get the title and set it // as the text for the TextView parentViewHolder .ParentItemTitle .setText(parentItem.getParentItemTitle()); // Create a layout manager // to assign a layout // to the RecyclerView. // Here we have assigned the layout // as LinearLayout with vertical orientation LinearLayoutManager layoutManager = new LinearLayoutManager( parentViewHolder .ChildRecyclerView .getContext(), LinearLayoutManager.HORIZONTAL, false ); // Since this is a nested layout, so // to define how many child items // should be prefetched when the // child RecyclerView is nested // inside the parent RecyclerView, // we use the following method layoutManager .setInitialPrefetchItemCount( parentItem .getChildItemList() .size()); // Create an instance of the child // item view adapter and set its // adapter, layout manager and RecyclerViewPool ChildItemAdapter childItemAdapter = new ChildItemAdapter( parentItem .getChildItemList()); parentViewHolder .ChildRecyclerView .setLayoutManager(layoutManager); parentViewHolder
|