📌  相关文章
📜  如何在 Android 中创建具有多个 ViewType 的 RecyclerView?

📅  最后修改于: 2022-05-13 01:54:31.411000             🧑  作者: Mango

如何在 Android 中创建具有多个 ViewType 的 RecyclerView?

RecyclerView 构成了 Android App 开发中 UI 的一个非常重要的部分。在显示一长串项目期间优化内存消耗尤为重要。 RecylerView 会扩充自定义的项目列表。此列表可以具有所有相似的布局或多个不同的布局。在这里,开发了这样一个具有多个ViewTypes的RecyclerView。以下是具有多个视图的 Android RecyclerView 示例。
多视图类型

方法

第 1 步:添加所需的依赖项
在 Android Studio 中创建一个新项目,并在 Gradle Scripts 部分下的build.gradle(:app)中添加以下依赖项:

有关依赖项的更多最新版本,请单击此处。虽然第一个依赖项是强制性的,但第二个依赖项是可选的,具体取决于 UI 要求。单击立即同步并继续。

第二步:在activity_main.xml中实现RecyclerView

创建一个包含主 RecyclerView 的布局。在这里,它已在activity_main.xml文件中创建。给定的布局仅包含一个 Welcome TextView 和一个 RecyclerView,但是可以根据要求对其进行自定义。 activity_main.xml的代码如下所示。

activity_main.xml


  
    
    
  
    
    
  


layout_one.xml


  
    
    
  
        
        
        
  
            
            
  
        
    
  
    
    
  


layout_two.xml


    
    
  
        
        
        
  
            
            
  
            
            
  
                
                
  
                
  
            
        
  
    
    
    
  


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
    private int icon;
    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() { 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;
    }
}


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 itemClassList;
  
    // public constructor for this class
    public AdapterClass(List 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(int position)
    {
        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)
        {
            super(itemView);
            icon = itemView.findViewById(R.id.image);
            text_one = itemView.findViewById(R.id.text_one);
            text_two = itemView.findViewById(R.id.text_two);
            linearLayout
                = itemView.findViewById(R.id.linearlayout);
        }
  
        private void setViews(int image, String textOne,
                              String textTwo)
        {
            icon.setImageResource(image);
            text_one.setText(textOne);
            text_two.setText(textTwo);
        }
    }
  
    // In the onCreateViewHolder, inflate the
    // xml layout as per the viewType.
    // This method returns either of the
    // ViewHolder classes defined above,
    // depending upon the layout passed as a parameter.
  
    @NonNull
    @Override
    public RecyclerView.ViewHolder
    onCreateViewHolder(@NonNull ViewGroup parent,
                       int viewType)
    {
        switch (viewType) {
        case LayoutOne:
            View layoutOne
                = LayoutInflater.from(parent.getContext())
                      .inflate(R.layout.layout_one, parent,
                               false);
            return new LayoutOneViewHolder(layoutOne);
        case LayoutTwo:
            View layoutTwo
                = LayoutInflater.from(parent.getContext())
                      .inflate(R.layout.layout_two, parent,
                               false);
            return new LayoutTwoViewHolder(layoutTwo);
        default:
            return null;
        }
    }
  
    // In onBindViewHolder, set the Views for each element
    // of the layout using the methods defined in the
    // respective ViewHolder classes.
  
    @Override
    public void onBindViewHolder(
        @NonNull RecyclerView.ViewHolder holder,
        int position)
    {
  
        switch (itemClassList.get(position).getViewType()) {
        case LayoutOne:
  
            String text
                = itemClassList.get(position).getText();
            ((LayoutOneViewHolder)holder).setView(text);
  
            // The following code pops a toast message
            // when the item layout is clicked.
            // This message indicates the corresponding
            // layout.
            ((LayoutOneViewHolder)holder)
                .linearLayout.setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view)
                        {
  
                            Toast
                                .makeText(
                                    view.getContext(),
                                    "Hello from Layout One!",
                                    Toast.LENGTH_SHORT)
                                .show();
                        }
                    });
  
            break;
  
        case LayoutTwo:
            int image
                = itemClassList.get(position).geticon();
            String text_one
                = itemClassList.get(position).getText_one();
            String text_two
                = itemClassList.get(position).getText_two();
            ((LayoutTwoViewHolder)holder)
                .setViews(image, text_one, text_two);
            ((LayoutTwoViewHolder)holder)
                .linearLayout.setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view)
                        {
  
                            Toast
                                .makeText(
                                    view.getContext(),
                                    "Hello from Layout Two!",
                                    Toast.LENGTH_SHORT)
                                .show();
                        }
                    });
            break;
        default:
            return;
        }
    }
  
    // This method returns the count of items present in the
    // RecyclerView at any given time.
  
    @Override
    public int getItemCount()
    {
        return itemClassList.size();
    }
}


MainActivity.java
package com.example.android.multilayoutrecyclerview;
  
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
  
import android.os.Bundle;
import android.widget.Adapter;
  
import java.util.ArrayList;
import java.util.List;
  
public class MainActivity extends AppCompatActivity {
  
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
  
        // From the MainActivity, find the RecyclerView.
        RecyclerView recyclerView
            = findViewById(R.id.recyclerView);
  
        // Create and set the layout manager
        // For the RecyclerView.
        LinearLayoutManager layoutManager
            = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
  
        List itemClasses = new ArrayList<>();
  
        // pass the arguments
        itemClasses.add(new ItemClass(ItemClass.LayoutOne,
                                      "Item Type 1"));
        itemClasses.add(new ItemClass(ItemClass.LayoutOne,
                                      "Item Type 1"));
        itemClasses.add(new ItemClass(
            ItemClass.LayoutTwo, R.drawable.icon,
            "Item Type 2", "Text"));
        itemClasses.add(new ItemClass(ItemClass.LayoutOne,
                                      "Item Type 1"));
        itemClasses.add(new ItemClass(
            ItemClass.LayoutTwo, R.drawable.icon,
            "Item Type 2", "Text"));
        itemClasses.add(new ItemClass(
            ItemClass.LayoutTwo, R.drawable.icon,
            "Item Type 2", "Text"));
        itemClasses.add(new ItemClass(ItemClass.LayoutOne,
                                      "Item Type 1"));
        itemClasses.add(new ItemClass(
            ItemClass.LayoutTwo, R.drawable.icon,
            "Item Type 2", "Text"));
        AdapterClass adapterClass
            = new AdapterClass(itemClasses);
  
        AdapterClass adapter
            = new AdapterClass(itemClasses);
  
        // set the adapter
        recyclerView.setAdapter(adapter);
    }
}


第 3 步:添加所需的可绘制文件

在继续之前,请确保所有必要的可绘制资源都已添加到可绘制资源目录下。在本教程中,仅使用了以下图标:
图标二

第 4 步:创建所有项目布局

识别 RecyclerView 需要在布局资源目录下的单独 XML 文件中保存和实现它们的所有不同布局。在这里,已经创建了两个不同的布局。第一个在layout_one.xml中实现,第二个在layout_two.xml 中实现。第一个布局仅包含一个包裹在 CardView 中的 TextView。下面是它的实现。

layout_one.xml



  
    
    
  
        
        
        
  
            
            
  
        
    
  
    
    
  

第二项包含三个包裹在 CardView 中的元素。

  • 一个图像视图
  • 一个文本视图
  • 另一个字体大小相对较小的 TextView

layout_two.xml



    
    
  
        
        
        
  
            
            
  
            
            
  
                
                
  
                
  
            
        
  
    
    
    
  

第 5 步:创建一个 Item 类

创建一个Java类,其中包含与每个布局对应的公共构造函数。因此,这里在ItemClass 中创建了两个构造函数。 Java文件。除了构造函数之外,这里还声明了 getter 和 setter 方法。这样做是为了安全地访问 ItemClass 之外的私有变量。这就是ItemClass的方式。 Java查找上面创建的布局:

项目类。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
    private int icon;
    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() { 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 的内容。在多个 ViewType RecyclerView 的 Adapter 类中,除了常规的onCreateViewHolder()onBindViewHolder()getItemCount()方法之外,还重写了以下方法。 getItemViewType()方法只负责选择每个项目对应的布局。除了添加一个额外的方法外,其他更改包括为每个项目布局定义一个特定的 ViewHolder 类。按照给出的代码进行更深入的了解。

适配器类。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 itemClassList;
  
    // public constructor for this class
    public AdapterClass(List 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(int position)
    {
        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)
        {
            super(itemView);
            icon = itemView.findViewById(R.id.image);
            text_one = itemView.findViewById(R.id.text_one);
            text_two = itemView.findViewById(R.id.text_two);
            linearLayout
                = itemView.findViewById(R.id.linearlayout);
        }
  
        private void setViews(int image, String textOne,
                              String textTwo)
        {
            icon.setImageResource(image);
            text_one.setText(textOne);
            text_two.setText(textTwo);
        }
    }
  
    // In the onCreateViewHolder, inflate the
    // xml layout as per the viewType.
    // This method returns either of the
    // ViewHolder classes defined above,
    // depending upon the layout passed as a parameter.
  
    @NonNull
    @Override
    public RecyclerView.ViewHolder
    onCreateViewHolder(@NonNull ViewGroup parent,
                       int viewType)
    {
        switch (viewType) {
        case LayoutOne:
            View layoutOne
                = LayoutInflater.from(parent.getContext())
                      .inflate(R.layout.layout_one, parent,
                               false);
            return new LayoutOneViewHolder(layoutOne);
        case LayoutTwo:
            View layoutTwo
                = LayoutInflater.from(parent.getContext())
                      .inflate(R.layout.layout_two, parent,
                               false);
            return new LayoutTwoViewHolder(layoutTwo);
        default:
            return null;
        }
    }
  
    // In onBindViewHolder, set the Views for each element
    // of the layout using the methods defined in the
    // respective ViewHolder classes.
  
    @Override
    public void onBindViewHolder(
        @NonNull RecyclerView.ViewHolder holder,
        int position)
    {
  
        switch (itemClassList.get(position).getViewType()) {
        case LayoutOne:
  
            String text
                = itemClassList.get(position).getText();
            ((LayoutOneViewHolder)holder).setView(text);
  
            // The following code pops a toast message
            // when the item layout is clicked.
            // This message indicates the corresponding
            // layout.
            ((LayoutOneViewHolder)holder)
                .linearLayout.setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view)
                        {
  
                            Toast
                                .makeText(
                                    view.getContext(),
                                    "Hello from Layout One!",
                                    Toast.LENGTH_SHORT)
                                .show();
                        }
                    });
  
            break;
  
        case LayoutTwo:
            int image
                = itemClassList.get(position).geticon();
            String text_one
                = itemClassList.get(position).getText_one();
            String text_two
                = itemClassList.get(position).getText_two();
            ((LayoutTwoViewHolder)holder)
                .setViews(image, text_one, text_two);
            ((LayoutTwoViewHolder)holder)
                .linearLayout.setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view)
                        {
  
                            Toast
                                .makeText(
                                    view.getContext(),
                                    "Hello from Layout Two!",
                                    Toast.LENGTH_SHORT)
                                .show();
                        }
                    });
            break;
        default:
            return;
        }
    }
  
    // This method returns the count of items present in the
    // RecyclerView at any given time.
  
    @Override
    public int getItemCount()
    {
        return itemClassList.size();
    }
}

第 7 步:完成 MainActivity。Java

以下是MainActivity 中要实现的重要任务。 Java文件。

  • 将内容视图设置为已实现主要 RecyclerView 的 XML 活动,此处为activity_main.xml
  • 设置 RecyclerView 的布局。
  • 将参数传递给 RecyclerView。
  • 设置适配器。

主要活动。Java

package com.example.android.multilayoutrecyclerview;
  
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
  
import android.os.Bundle;
import android.widget.Adapter;
  
import java.util.ArrayList;
import java.util.List;
  
public class MainActivity extends AppCompatActivity {
  
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
  
        // From the MainActivity, find the RecyclerView.
        RecyclerView recyclerView
            = findViewById(R.id.recyclerView);
  
        // Create and set the layout manager
        // For the RecyclerView.
        LinearLayoutManager layoutManager
            = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
  
        List itemClasses = new ArrayList<>();
  
        // pass the arguments
        itemClasses.add(new ItemClass(ItemClass.LayoutOne,
                                      "Item Type 1"));
        itemClasses.add(new ItemClass(ItemClass.LayoutOne,
                                      "Item Type 1"));
        itemClasses.add(new ItemClass(
            ItemClass.LayoutTwo, R.drawable.icon,
            "Item Type 2", "Text"));
        itemClasses.add(new ItemClass(ItemClass.LayoutOne,
                                      "Item Type 1"));
        itemClasses.add(new ItemClass(
            ItemClass.LayoutTwo, R.drawable.icon,
            "Item Type 2", "Text"));
        itemClasses.add(new ItemClass(
            ItemClass.LayoutTwo, R.drawable.icon,
            "Item Type 2", "Text"));
        itemClasses.add(new ItemClass(ItemClass.LayoutOne,
                                      "Item Type 1"));
        itemClasses.add(new ItemClass(
            ItemClass.LayoutTwo, R.drawable.icon,
            "Item Type 2", "Text"));
        AdapterClass adapterClass
            = new AdapterClass(itemClasses);
  
        AdapterClass adapter
            = new AdapterClass(itemClasses);
  
        // set the adapter
        recyclerView.setAdapter(adapter);
    }
}

输出:在模拟器上运行