How to implement multiple recyclerviews in one layout?
Asked Answered
W

5

5

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.

Waffle answered 5/6, 2018 at 17:40 Comment(0)
D
7

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.

Denary answered 5/6, 2018 at 18:24 Comment(3)
Thanks for great example. However, could you explain me, how onCreateViewHolder knows the correct viewType? Where do you set that?Waffle
You can modify the getItemViewType(). Right now, it returns the numbers I put in while creating adapter object. If it has a 0, the item will be treated as a textview, if the number is 1, upper recyclerview's item and 2 for lower recyclerview's item.Denary
If this worked for you, can you accept my answer as correct please?Denary
I
1

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.

Ira answered 5/6, 2018 at 17:58 Comment(2)
No, just NO! This is a horrible practice that defies the purpose of RecyclerView as it keeps all of the views in memory, all the time and has nothing to recycle / loose the memory engagement.Ria
Thanks for your comment :)Ira
S
1

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.

Schram answered 5/6, 2018 at 18:1 Comment(5)
I need to display "my items" and "all items" after that. Maybe there would be one more "section". How it can be done with one recyclerView? Wouldn't maintaining only one RecyclerView lead to more complexity?Waffle
The key for maintaining multiple sections is the onCreateViewHolder(parent: ViewGroup, viewType: Int) method of RecyclerView Adapter where you can decide what type of view it is and inflate the view accordingly.Schram
There are many libraries to make this job easier than to set up everything by ourself. Check out this post (or similar ones) for more details if you want to setup from scratch.Schram
Very good apps like facebook, youtube, netflix and even the play store use two or more RV in the same layout (for the looks of them)Ira
Are you referring to horizontal scrolling list inside a vertical scrolling list?Schram
B
1

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.

Balduin answered 31/10, 2018 at 13:58 Comment(0)
O
0

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.

Ouse answered 19/7, 2023 at 8:55 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewBianchi

© 2022 - 2024 — McMap. All rights reserved.