Как создать RecyclerView с несколькими типами просмотра в Android?

Опубликовано: 5 Января, 2022

RecyclerView составляет очень важную часть пользовательского интерфейса при разработке приложений для Android. Особенно важно оптимизировать потребление памяти при отображении длинного списка элементов. RecylerView расширяет настраиваемый список элементов. В этом списке могут быть как все похожие макеты, так и несколько разных макетов. Вот такой RecyclerView с несколькими ViewTypes разработан. Ниже приведен пример Android RecyclerView с несколькими представлениями.

Подход

Шаг 1. Добавьте необходимые зависимости
Создайте новый проект в Android Studio и добавьте следующие зависимости в build.gradle (: app) в разделе Gradle Scripts:

implementation “androidx.recyclerview:recyclerview:1.1.0”
implementation “androidx.cardview:cardview:1.0.0”

Для получения более свежих версий зависимостей щелкните здесь. Хотя первая зависимость является обязательной, вторая не является обязательной в зависимости от требований пользовательского интерфейса. Нажмите « Синхронизировать сейчас» и продолжите.

Шаг 2. Внедрите RecyclerView в activity_main.xml

Создайте макет, содержащий основной RecyclerView. Здесь он был создан в файле activity_main.xml. Данный макет содержит просто приветствие TextView и RecyclerView, однако его можно настроить в соответствии с требованиями. Код для activity_main.xml приведен ниже.

activity_main.xml

<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".MainActivity" >
<!--Welcome text-->
< TextView
android:id = "@+id/heading"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "Welcome to GFG!"
android:textColor = "#006600"
android:textSize = "20dp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent"
app:layout_constraintVertical_bias = "0.058" ></ TextView >
<!-- Main RecyclerView-->
< androidx.recyclerview.widget.RecyclerView
android:id = "@+id/recyclerView"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_marginTop = "15dp"
android:layout_marginStart = "15dp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/heading"
app:layout_constraintVertical_bias = "0.061"
android:paddingBottom = "100dp" />
</ androidx.constraintlayout.widget.ConstraintLayout >

Шаг 3: Добавьте требуемый файл с возможностью рисования

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

Шаг 4. Создайте макеты всех элементов.

Определите все различные макеты, которые должен содержать RecyclerView, и реализовать их все в отдельных файлах XML в каталоге ресурсов макета. Здесь были созданы два разных макета. Первый реализован в layout_one.xml, а второй - в layout_two.xml. Первый макет состоит только из TextView, заключенного в CardView. Ниже приводится его реализация.

layout_one.xml

<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:orientation = "vertical" >
<!--parent CardView-->
< androidx.cardview.widget.CardView
android:id = "@+id/cardview_one"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_marginTop = "4dp"
android:layout_marginEnd = "16dp"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintTop_toTopOf = "parent"
android:elevation = "5dp" >
<!--LinearLayout inside the CardView-->
<!--This layout is accessed to create
toasts when this item is clicked-->
< LinearLayout
android:id = "@+id/linearlayout"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:orientation = "horizontal" >
<!--This layout only holds a TextView
inside a CardView-->
< TextView
android:id = "@+id/text"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:textColor = "#000000"
android:textSize = "20dp"
android:layout_margin = "20dp" />
</ LinearLayout >
</ androidx.cardview.widget.CardView >
<!-- This is extra space given to maintain a
gap between two consecutive CardViews-->
< Space
android:layout_width = "match_parent"
android:layout_height = "10dp" />
</ LinearLayout >

Второй элемент содержит три элемента, заключенных в CardView.

  • ImageView
  • TextView
  • Другой TextView с относительно меньшим размером шрифта

layout_two.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:id="@+id/linearlayout"
    >
    <!--parent CardView-->
    <androidx.cardview.widget.CardView
        android:id="@+id/cardview_two"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:layout_marginEnd="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:elevation="5dp">
  
        <!--LinearLayout inside the CardView-->
        <!--This layout is accessed to create
             toasts when this item is clicked-->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">
  
            <!--This layout consists of an ImageView 
                and two TextViews-->
            <ImageView
                android:id="@+id/image"
                android:layout_width="80dp"
                android:layout_height="80dp"/>
  
            <!-- The purpose of this LinearLayout  is 
                 to align the two TextViews Vertically-->
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:orientation="vertical">
  
                <!--These are the 2 TextViews in this layout-->
                <TextView
                    android:id="@+id/text_one"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:layout_marginStart="20dp"
                    android:textColor="#000000"
                    android:textSize="20dp"/>
  
                <TextView
                    android:id="@+id/text_two"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="#000000"
                    android:textSize="15dp"
                    android:layout_marginTop="10dp"
                    android:layout_marginStart="20dp"/>
  
            </LinearLayout>
        </LinearLayout>
  
    </androidx.cardview.widget.CardView>
    <!-- This is extra space given to 
         maintain a gap between two CardViews-->
    <Space
        android:layout_width="match_parent"
        android:layout_height="10dp"/>
  
</LinearLayout>

Шаг 5: Создайте класс элемента

Создайте класс Java, содержащий общедоступные конструкторы, соответствующие каждому макету. Таким образом, здесь в файле ItemClass.java были созданы два конструктора. Помимо конструкторов здесь объявлены методы получения и установки. Это сделано для безопасного доступа к закрытым переменным ItemClass вне его. Вот как ItemClass.java ищет макеты, созданные выше:

ItemClass.java

package com.example.android.multilayoutrecyclerview;
// ItemClass
public class ItemClass {
// Integers assigned to each layout
// these are declared static so that they can
// be accessed from the class name itself
// And final so that they are not modified later
public static final int LayoutOne = 0 ;
public static final int LayoutTwo = 1 ;
// This variable ViewType specifies
// which out of the two layouts
// is expected in the given item
private int viewType;
// String variable to hold the TextView
// of the first item.
private String text;
// public constructor for the first layout
public ItemClass( int viewType, String text)
{
this .text = text;
this .viewType = viewType;
}
// getter and setter methods for the text variable
public String getText() { return text; }
public void setText(String text) { this .text = text; }
// Variables for the item of second layout
icon; private int
private String text_one, text_two;
// public constructor for the second layout
public ItemClass( int viewType, int icon, String text_one,
String text_two)
{
this .icon = icon;
this .text_one = text_one;
this .text_two = text_two;
this .viewType = viewType;
}
// getter and setter methods for
// the variables of the second layout
public int geticon() { icon; } return icon; }
public void seticon( int icon) { this .icon = icon; }
public String getText_one() { return text_one; }
public void setText_one(String text_one)
{
this .text_one = text_one;
}
public String getText_two() { return text_two; }
public void setText_two(String text_two)
{
this .text_two = text_two;
}
public int getViewType() { return viewType; }
public void setViewType( int viewType)
{
this .viewType = viewType;
}
}

Шаг 6. Создайте класс адаптера

Создайте класс адаптера для отображения содержимого RecyclerView. В классе Adapter для нескольких ViewType RecyclerViews следующий метод переопределяется в дополнение к обычным onCreateViewHolder() , onBindViewHolder() и getItemCount() . getItemViewType() несет полную ответственность за выбор макета, соответствующего каждому элементу. Помимо добавления дополнительного метода, другие изменения включают определение определенного класса ViewHolder для каждого макета элемента. Следуйте приведенному коду для более глубокого понимания.

AdapterClass.java

package com.example.android.multilayoutrecyclerview;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
import static com.example.android.multilayoutrecyclerview.ItemClass.LayoutOne;
import static com.example.android.multilayoutrecyclerview.ItemClass.LayoutTwo;
public class AdapterClass extends RecyclerView.Adapter {
private List<ItemClass> itemClassList;
// public constructor for this class
public AdapterClass(List<ItemClass> itemClassList)
{
this .itemClassList = itemClassList;
}
// Override the getItemViewType method.
// This method uses a switch statement
// to assign the layout to each item
// depending on the viewType passed
@Override
public int getItemViewType( position) int
{
switch (itemClassList.get(position).getViewType()) {
case 0 :
return LayoutOne;
case 1 :
return LayoutTwo;
default :
return - 1 ;
}
}
// Create classes for each layout ViewHolder.
class LayoutOneViewHolder
extends RecyclerView.ViewHolder {
private TextView textview;
private LinearLayout linearLayout;
public LayoutOneViewHolder( @NonNull View itemView)
{
super (itemView);
// Find the Views
textview = itemView.findViewById(R.id.text);
linearLayout
= itemView.findViewById(R.id.linearlayout);
}
// method to set the views that will
// be used further in onBindViewHolder method.
private void setView(String text)
{
textview.setText(text);
}
}
// similarly a class for the second layout is also
// created.
class LayoutTwoViewHolder
extends RecyclerView.ViewHolder {
private ImageView icon;
private TextView text_one, text_two;
private LinearLayout linearLayout;
public LayoutTwoViewHolder( @NonNull View itemView)