How to implement multiple recyclerviews in one layout?

11k views Asked by At

I want to create a pane in which there are two RecyclerViews (let's say 'MyItems', 'AllItems'). I have created vertical LinearLayout, in which there are TextView as title and RecyclerView. Something like this:

enter image description here

 <LinearLayout ... >

    <TextView
        android:text="My Items"
        ... />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_items"
        ... />

    <TextView
        android:text="All Items"
        ... />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/all_items"
        ... />

</LinearLayout>

However with this approach, only recyclerViews are scrollable independently, but I need the whole layout to be scrollable only (so firstly it scrolls through first section, then second). I tried to wrap it up in ScrollView and NestedScrollView, but the closest I got was scrolling without smooth animation.

My question is, is this approach valid, and if so, is there a way to add smooth scrolling in NestedScrollView? Or should I implement this using another approach, e.g. create ListView that contains two items with layout containing TextView and RecyclerView?

ListView

  • List item 1

    • Title 1
    • RecyclerView 1
  • List item 2

    • Title 2
    • RecyclerView2

I believe this approach is not good from performance side of view. Am I right? I just need to find the best practice for this. Thank you.

5

There are 5 answers

3
Shashwat On BEST ANSWER

Please don't use nested scrolling. It will defeat the purpose of recycler view and will keep everything inside the memory as the height will be set to maximum for both the recyclers. Instead proceed with the following two choices:

1.If you don't have a specific background, create a single RecyclerView with adapter similar to the following:

public class MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

    ArrayList<Integer> data = new ArrayList<>();
    private final int VIEW_TYPE_TEXTVIEW = 0;
    private final int VIEW_TYPE_ITEM_1 = 1;
    private final int VIEW_TYPE_ITEM_2 = 2;
    private final LayoutInflater inflater;
    private final ArrayList<Integer> data;

    public MyRecyclerAdapter(Context ctx, ArrayList<Integer> data){
        this.context = ctx;
        this.data = data;
        inflater = LayoutInflater.from(context);
    }

    @Override
    public int getItemViewType(int position) {
        return data.get(position);
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if(viewType == VIEW_TYPE_TEXTVIEW){
            View view = inflater.inflate(R.layout.simple_textview, parent, false);
            return new TextViewHolder(view);
        }else if(viewType == VIEW_TYPE_ITEM_1){
            View view = inflater.inflate(R.layout.item_top_recycler, parent, false);
            return new Item1Holder(view);
        }else{
            View view = inflater.inflate(R.layout.item_bottom_recycler, parent, false);
            return new Item2Holder(view);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if(holder instanceof TextViewHolder){
            ((TextViewHolder) holder).textView.setText(...);
        }else if(holder instanceof Item1Holder){
            ((Item1Holder) holder).itemTextView.setText(...);
        }else if(holder instanceof Item2Holder){
            ((Item2Holder) holder).itemTextView.setText(...);
        }
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    class TextViewHolder extends RecyclerView.ViewHolder {


        TextView textView;

        public HeaderHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.tv);
        }
    }
    class Item1Holder extends RecyclerView.ViewHolder {


        TextView itemTextView;

        public HeaderHolder(View itemView) {
            super(itemView);
            itemTextView = itemView.findViewById(R.id.tv);
        }
    }
    class Item2Holder extends RecyclerView.ViewHolder {


        TextView itemTextView;

        public HeaderHolder(View itemView) {
            super(itemView);
            itemTextView = itemView.findViewById(R.id.tv);
        }
    }
}

Then set your adapter like following:

ArrayList<Integer> data = new ArrayList<>();
//Adding first textview
data.add(0);
//Adding 10 elements of first RecyclerView
for(int i = 0; i<10; i++){
    data.add(1);
}
//Adding second textview
data.add(0);
//Adding 10 elements of second RecyclerView
for(int i = 0; i<10; i++){
    data.add(2);
}

adapter = new MyRecyclerAdapter(this, data);
navView.setAdapter(adapter);

This way, you can use the RecyclerView to contain your textview too. This method will give you the best optimization. Make sure that you return the appropriate VIEW_TYPE in getItemViewType() for your upper recyclerView, lower RecyclerView and the TextViews.

The second method is to have one RecyclerView containing 4 items:

  • TextView
  • LinearLayout
  • TextView
  • LinearLayout

Then populate these LinearLayouts with items dynamically. This will ensure that at least one of the Linearlayout is recycled when out of view. Even then, the first approach will be a far better approach than this.

2
Levi Moreira On

You should try the NestedScrollView solution that you said was the closest to what you wanted:

NestedScrollView
   TextView
   RecyclerView
   TextView
   RecyclerView

And to have the smooth scroll you need to set a property in your recycler views:

 recyclerView.setNestedScrollingEnabled(false);

That way your layout will scroll the NestedScrollView rather then the RVs.

5
Kalyan Dechiraju On

First of all it's not a good idea to have two recycler views in one screen unless there is a strong reason for that. Try with different sections with headers in one recycler view.

If you still want to use, embed the layout in NestedScrollView and set the recyclerView's nestedScrollingEnabled property to false

recyclerView.setNestedScrollingEnabled(false);

Tip: Check out FastAdapter which makes the job easier.

0
Benson Githinji On

Whatever you are trying to achieve is better done as illustrated in the link below: http://khmertechtrain.tk/index.php/2017/10/03/create-a-vertical-scroll-and-horizontal-scroll-app-like-google-play-store/

Also, you will need to make use of the RecycledViewPool in order to share Views between multiple RecyclerViews if at all the views will be similar.

1
Shubham Pandey On

If you need to integrate multiple recyclerview in single screen. Never used nested scrollview it will restrict your recyclerview to recycler views that will create performance issue also it will take more memory.
People suggest to use recyclerView.setNestedScrollingEnabled(false); But this is not recycle the views.
Best way is to use with single recyclerview with multiple view type that is the only way to make recyclerview performance fast.