📌  相关文章
📜  如何在 Android 中创建嵌套的 RecyclerView

📅  最后修改于: 2021-10-28 02:47:41             🧑  作者: Mango

嵌套的 RecyclerViewRecyclerView 中 RecyclerView的实现。这种布局的一个例子可以在各种应用程序中看到,例如 Play 商店,其中外部(父)RecyclerView 是垂直方向,而内部(子)RecyclerViews 是水平方向。这里开发了类似的布局。
方法:
第一步:添加需要的依赖
build.gradle(:app)文件中添加以下依赖。 RecyclerView 对应的第一个依赖是必填的,第二个是 CardView 的依赖,因此根据 UI 要求它是可选的。由于这里在子RecyclerView布局中使用了CardView,所以添加了CardView的依赖。
注意:添加依赖项后,单击立即同步。

注意:对于正确版本的依赖项,请在此处检查。
第二步:实现父RecyclerView
父 RecyclerView 在activity_main文件中实现。此处,activity_main 文件仅包含父 RecyclerView,但可以根据需要对其进行自定义。

activity_main


  
    
    
  


parent_item


  
    
  
    
  
        
  
            
            
        
  
  


child_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 ChildItemList;
  
    // Constructor of the class
    // to initialize the variables
    public ParentItem(
        String ParentItemTitle,
        List 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 getChildItemList()
    {
        return ChildItemList;
    }
  
    public void setChildItemList(
        List childItemList)
    {
        ChildItemList = childItemList;
    }
}


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 {
  
    private List ChildItemList;
  
    // Constructor
    ChildItemAdapter(List 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,
        int position)
    {
  
        // 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
        // i.e. 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 {
  
    // 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 itemList;
  
    ParentItemAdapter(List 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,
        int position)
    {
  
        // 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
            .ChildRecyclerView
            .setAdapter(childItemAdapter);
        parentViewHolder
            .ChildRecyclerView
            .setRecycledViewPool(viewPool);
    }
  
    // This method returns the number
    // of items we have added in the
    // ParentItemList i.e. the number
    // of instances we have created
    // of the ParentItemList
    @Override
    public int getItemCount()
    {
  
        return itemList.size();
    }
  
    // This class is to initialize
    // the Views present in
    // the parent RecyclerView
    class ParentViewHolder
        extends RecyclerView.ViewHolder {
  
        private TextView ParentItemTitle;
        private RecyclerView ChildRecyclerView;
  
        ParentViewHolder(final View itemView)
        {
            super(itemView);
  
            ParentItemTitle
                = itemView
                      .findViewById(
                          R.id.parent_item_title);
            ChildRecyclerView
                = itemView
                      .findViewById(
                          R.id.child_recyclerview);
        }
    }
}


MainActivity
package com.example.nestedrecyclerview;
  
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
  
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);
  
        RecyclerView
            ParentRecyclerViewItem
            = findViewById(
                R.id.parent_recyclerview);
  
        // Initialise the Linear layout manager
        LinearLayoutManager
            layoutManager
            = new LinearLayoutManager(
                MainActivity.this);
  
        // Pass the arguments
        // to the parentItemAdapter.
        // These arguments are passed
        // using a method ParentItemList()
        ParentItemAdapter
            parentItemAdapter
            = new ParentItemAdapter(
                ParentItemList());
  
        // Set the layout manager
        // and adapter for items
        // of the parent recyclerview
        ParentRecyclerViewItem
            .setAdapter(parentItemAdapter);
        ParentRecyclerViewItem
            .setLayoutManager(layoutManager);
    }
  
    private List ParentItemList()
    {
        List itemList
            = new ArrayList<>();
  
        ParentItem item
            = new ParentItem(
                "Title 1",
                ChildItemList());
        itemList.add(item);
        ParentItem item1
            = new ParentItem(
                "Title 2",
                ChildItemList());
        itemList.add(item1);
        ParentItem item2
            = new ParentItem(
                "Title 3",
                ChildItemList());
        itemList.add(item2);
        ParentItem item3
            = new ParentItem(
                "Title 4",
                ChildItemList());
        itemList.add(item3);
  
        return itemList;
    }
  
    // Method to pass the arguments
    // for the elements
    // of child RecyclerView
    private List ChildItemList()
    {
        List ChildItemList
            = new ArrayList<>();
  
        ChildItemList.add(new ChildItem("Card 1"));
        ChildItemList.add(new ChildItem("Card 2"));
        ChildItemList.add(new ChildItem("Card 3"));
        ChildItemList.add(new ChildItem("Card 4"));
  
        return ChildItemList;
    }
}


第 3 步:为父 RecyclerView 创建项目布局
确定父布局的需求并在 XML 布局文件中添加与它们对应的视图。在这里,布局文件被命名为parent_item 。除了子 RecyclerView 之外,还包括标题的 TextView。

父项



  
    
  
    
  
        
  
            
            
        
  
  

第 4 步:为子 RecyclerView 创建项目布局
子 RecyclerView 的项目布局是在名为child_item的 XML 布局文件中创建的。 Child RecyclerView 包括一个 ImageView 和一个 TextView,两者都包裹在 CardView 中。
下图作为ImageView的资源,因此添加到drawable资源文件夹中。

图标

child_item



  
    
    
        
  
            
            
            
            
  
            
  
                
                
            
        
    
  

第 5 步:为每个 RecyclerView 创建 Item 类。
每个 RecyclerView 都需要一个Java类,其中构造函数初始化项目的参数并声明 getter 和 setter 方法。因此,创建以下Java类:

  • ChildItem:该类将为我们希望动态设置的child_item布局的视图实现构造函数、getter 和 setter 方法。
  • ParentItem:该类将为我们希望动态设置的parent_item布局的视图实现构造函数、getter 和 setter 方法。

子项

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;
    }
}

父项

package com.example.nestedrecyclerview;
  
import java.util.List;
  
public class ParentItem {
  
    // Declaration of the variables
    private String ParentItemTitle;
    private List ChildItemList;
  
    // Constructor of the class
    // to initialize the variables
    public ParentItem(
        String ParentItemTitle,
        List 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 getChildItemList()
    {
        return ChildItemList;
    }
  
    public void setChildItemList(
        List childItemList)
    {
        ChildItemList = childItemList;
    }
}

第 6 步:为每个 RecyclerViews 创建一个 Adapter 类。
需要一个适配器类来传递要在 RecyclerView 的视图中显示的数据。
ChildItem 和 ParentItem 类都需要一个适配器类。

  • ChildAdapter:这是用于保存要在 ChildItem 类的视图中显示的信息的适配器类。
  • ParentAdapter:这是用于保存要在 ParentItem 类的视图中显示的信息的适配器类。

在 ParentItemAdapter 类中,创建了该类的一个实例

该类用于在父 RecyclerView 和子 RecyclerView 之间传递 View。

子项适配器

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 {
  
    private List ChildItemList;
  
    // Constructor
    ChildItemAdapter(List 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,
        int position)
    {
  
        // 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
        // i.e. 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);
        }
    }
}

父项适配器

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 {
  
    // 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 itemList;
  
    ParentItemAdapter(List 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,
        int position)
    {
  
        // 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
            .ChildRecyclerView
            .setAdapter(childItemAdapter);
        parentViewHolder
            .ChildRecyclerView
            .setRecycledViewPool(viewPool);
    }
  
    // This method returns the number
    // of items we have added in the
    // ParentItemList i.e. the number
    // of instances we have created
    // of the ParentItemList
    @Override
    public int getItemCount()
    {
  
        return itemList.size();
    }
  
    // This class is to initialize
    // the Views present in
    // the parent RecyclerView
    class ParentViewHolder
        extends RecyclerView.ViewHolder {
  
        private TextView ParentItemTitle;
        private RecyclerView ChildRecyclerView;
  
        ParentViewHolder(final View itemView)
        {
            super(itemView);
  
            ParentItemTitle
                = itemView
                      .findViewById(
                          R.id.parent_item_title);
            ChildRecyclerView
                = itemView
                      .findViewById(
                          R.id.child_recyclerview);
        }
    }
}

步骤 7:设置父 RecyclerView 的布局并将参数传递给两个 RecyclerView。要传递给 RecyclerViews 的参数在Java类中给出,该类膨胀父 RecyclerView 的活动(此处为 activity_main)。所以这里的参数将在 MainActivity 文件中传递。
此外,在此处为父 RecyclerView 设置布局。

主要活动

package com.example.nestedrecyclerview;
  
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
  
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);
  
        RecyclerView
            ParentRecyclerViewItem
            = findViewById(
                R.id.parent_recyclerview);
  
        // Initialise the Linear layout manager
        LinearLayoutManager
            layoutManager
            = new LinearLayoutManager(
                MainActivity.this);
  
        // Pass the arguments
        // to the parentItemAdapter.
        // These arguments are passed
        // using a method ParentItemList()
        ParentItemAdapter
            parentItemAdapter
            = new ParentItemAdapter(
                ParentItemList());
  
        // Set the layout manager
        // and adapter for items
        // of the parent recyclerview
        ParentRecyclerViewItem
            .setAdapter(parentItemAdapter);
        ParentRecyclerViewItem
            .setLayoutManager(layoutManager);
    }
  
    private List ParentItemList()
    {
        List itemList
            = new ArrayList<>();
  
        ParentItem item
            = new ParentItem(
                "Title 1",
                ChildItemList());
        itemList.add(item);
        ParentItem item1
            = new ParentItem(
                "Title 2",
                ChildItemList());
        itemList.add(item1);
        ParentItem item2
            = new ParentItem(
                "Title 3",
                ChildItemList());
        itemList.add(item2);
        ParentItem item3
            = new ParentItem(
                "Title 4",
                ChildItemList());
        itemList.add(item3);
  
        return itemList;
    }
  
    // Method to pass the arguments
    // for the elements
    // of child RecyclerView
    private List ChildItemList()
    {
        List ChildItemList
            = new ArrayList<>();
  
        ChildItemList.add(new ChildItem("Card 1"));
        ChildItemList.add(new ChildItem("Card 2"));
        ChildItemList.add(new ChildItem("Card 3"));
        ChildItemList.add(new ChildItem("Card 4"));
  
        return ChildItemList;
    }
}

输出: