2

I have a recyclerview and within it I am trying to add a nested recyclerview that contains a list. Here is what I am trying to make: My Desired output

This is the closest solution I could find on stack overflow but they use headers instead of left-aligned titles that wrap all other nested views. How do I create a nested list within a nested recyclerview within a recyclerview?

Bread
  • 71
  • 1
  • 13
  • We need two recyclerViews and two Adapters which i call inner and outter.inside ViewHolder of outter adapter put innerRecyclerview and inside onBindViewHolder of outter adapter set adapter to innerRecyclerView – Salar Arabpour Feb 15 '20 at 21:39
  • @SalarArabpour This sounds like a good solution. Do you think my approach to the idea could be better? I feel like I am thinking of using too many recycler views to get what I want. I am only trying to make a dynamic list of items within a main list of fixed items. – Bread Feb 15 '20 at 21:45
  • 1
    I can assure you doing this with two recyclerviews is the best option. I will post you an example code tommorow when i access my laptop! – Salar Arabpour Feb 15 '20 at 22:20
  • @SalarArabpour you are incredible! – Bread Feb 15 '20 at 22:54

1 Answers1

8

We need two RecyclerViews and two Adapters which i call inner and outer.inside ViewHolder of outer adapter put innerRecyclerView and inside onBindViewHolder of outer adapter set adapter to innerRecyclerView.i recently developed a test project like this

here is outerAdapter

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

private Context context;
private List<Category> categories;
private List<Ads> ads_list;
private List<Products> productsList;
private int count;
private int width;

public MainAdapter(Context context, List<Category> categories, List<Ads> ads_list,List<Products> productsList,int width) {
    this.context = context;
    this.categories = categories;
    this.ads_list = ads_list;
    this.productsList=productsList;
    this.width=width;
    //Helper.logDebug("main__adapter",String.valueOf(categories.size()));
    //Helper.logDebug("main_adapter","haminjoori");
}

private class ViewHolder extends RecyclerView.ViewHolder{
    private RecyclerView recyclerView;
    private TextView tv_type,ad_tv_image_address;
    private ImageView iv_ad;

    public ViewHolder(@NonNull View itemView) {
        super(itemView);

        recyclerView=itemView.findViewById(R.id.recyclerview_horizental);
        recyclerView.setNestedScrollingEnabled(false);
        tv_type=itemView.findViewById(R.id.tv_type);
        iv_ad=itemView.findViewById(R.id.iv_ad);
        ad_tv_image_address=itemView.findViewById(R.id.ad_image_address);
        //Helper.logDebug("main_adapter","haminjoori");
    }
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
    View view= LayoutInflater.from(context).inflate(R.layout.recycler_layout,viewGroup,false);
    //Helper.logDebug("main_adapter","haminjoori");
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
    ViewHolder holder= (ViewHolder) viewHolder;
    try {
        String banner_url=ads_list.get(i).getImage();
        holder.ad_tv_image_address.setText(banner_url);
        Picasso.get().load(context.getString(R.string.base_url_banner)+banner_url).into(holder.iv_ad);
    }catch (Exception ex){
        holder.ad_tv_image_address.setText("");
    }
    Helper.logDebug("main_adapter",holder.ad_tv_image_address.getText().toString());
    holder.tv_type.setText(categories.get(i).getName());
    SecondAdapter secondAdapter=new SecondAdapter(categories.get(i).getProducts(),context,width);
    LinearLayoutManager layoutManager=new LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false);

    holder.recyclerView.setLayoutManager(layoutManager);
    holder.recyclerView.setAdapter(secondAdapter);



}

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

and here is inner adapter

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

private Context context;
private int count;
private List<Products> productsList;
private List<Category> categories;
private int width;

public SecondAdapter(List<Products> productsList, Context context,int width) {
    this.productsList = productsList;
    this.context = context;
    this.width=width;
}

private class ViewHolder extends RecyclerView.ViewHolder {
    private TextView market_price,our_price,name,unit,min_amount,image;
    private ImageView imagee;
    public ViewHolder(@NonNull View itemView) {
        super(itemView);
        itemView.getLayoutParams().width=width/2;


        market_price=itemView.findViewById(R.id.product_market_price);
        our_price=itemView.findViewById(R.id.product_our_price);
        name=itemView.findViewById(R.id.fruit_name);
        unit=itemView.findViewById(R.id.fruit_unit);
        image=itemView.findViewById(R.id.product_image_url);
        imagee=itemView.findViewById(R.id.iv_rec);
        min_amount=itemView.findViewById(R.id.product_min_amount);

        Log.d("second_adapter","haminjoori");
    }
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
    View view= LayoutInflater.from(context).inflate(R.layout.recycler2_layout,viewGroup,false);
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
    ViewHolder holder= (ViewHolder) viewHolder;
    Helper.logDebug("second_adapter","haminjori");

    holder.name.setText(productsList.get(i).getName());
    holder.unit.setText(productsList.get(i).getUnit());
    holder.market_price.setText(String.valueOf(productsList.get(i).getMarketPrice()));
    holder.our_price.setText(String.valueOf(productsList.get(i).getOurPrice()));
    Helper.logDebug("secondAdapter",productsList.get(i).getImage());
    String address=productsList.get(i).getImage();
    address=address.substring(6);
    holder.image.setText(address);
    String full_address=context.getString(R.string.base_url_image)+address;
    Helper.logDebug("secondAdapter",full_address);
    Picasso.get().load(full_address).into(holder.imagee);
    holder.min_amount.setText(String.valueOf(productsList.get(i).getMin_amount()));
}

@Override
public int getItemCount() {

    Helper.logDebug("second_adapter",String.valueOf(productsList.size()));
    return productsList.size();
}
}

outer view adapter xml

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:app="http://schemas.android.com/apk/res-auto" 
xmlns:tools="http://schemas.android.com/tools"         
android:layout_height="wrap_content" android:layout_width="match_parent" 
xmlns:android="http://schemas.android.com/apk/res/android">

  <TextView android:layout_height="wrap_content" 
  android:layout_width="wrap_content" android:text="نوع میوه" 
  android:layout_marginBottom="4dp" android:layout_marginTop="4dp" 
  android:layout_centerHorizontal="true" style="@style/main_titles" 
  android:id="@+id/tv_type"/>

  <ImageView android:layout_height="wrap_content" 
  android:layout_width="wrap_content" 
  android:src="@drawable/ic_keyboard_arrow_right_black_24dp" 
  android:layout_alignParentRight="true"/>

  <android.support.v7.widget.RecyclerView 
  android:layout_height="wrap_content" android:layout_width="match_parent" 
  android:id="@+id/recyclerview_horizental" 
  android:layout_below="@id/tv_type" 
  app:layoutManager="android.support.v7.widget.LinearLayoutManager" 
  android:orientation="horizontal" 
  tools:listitem="@layout/recycler2_layout"/>

  <TextView android:layout_height="wrap_content" 
  android:layout_width="wrap_content" android:id="@+id/ad_image_address" 
  android:visibility="gone"/>

  <ImageView android:layout_height="80dp" android:layout_width="match_parent" 
  android:id="@+id/iv_ad" 
  android:layout_below="@id/recyclerview_horizental"/>

  </RelativeLayout>

inner view adapter xml

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:orientation="horizontal" 
android:layout_height="wrap_content" android:layout_width="match_parent" 
xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout android:layout_height="wrap_content" 
android:layout_width="0dp" android:layout_weight="1" 
android:id="@+id/rel_layout">

<ImageView android:layout_height="200dp" android:layout_width="match_parent" 
android:id="@+id/iv_rec"/>

<TextView android:layout_height="wrap_content" 
android:layout_width="wrap_content" android:id="@+id/fruit_name" 
android:textColor="@color/semi_black" android:textSize="14sp" 
android:layout_marginRight="8dp" android:layout_below="@id/iv_rec" 
android:layout_alignParentRight="true" android:text="نام میوه"/>

<TextView android:layout_height="wrap_content" 
android:layout_width="wrap_content" android:id="@+id/fruit_unit" 
android:textColor="@color/black_white" android:textSize="12sp" 
android:layout_below="@id/iv_rec" android:text="واحد" 
android:layout_alignParentLeft="true" android:layout_marginLeft="8dp"/>

<TextView android:layout_height="wrap_content" 
android:layout_width="wrap_content" android:id="@+id/product_market_price" 
android:textColor="@color/semi_black" android:textSize="12sp" 
android:layout_below="@id/fruit_unit" android:text="قیمت مارکت" 
android:layout_alignParentLeft="true" android:layout_marginLeft="8dp"/>

<TextView android:layout_height="wrap_content" 
android:layout_width="wrap_content" android:id="@+id/product_our_price" 
android:textColor="@color/semi_black" android:textSize="12sp" 
android:layout_below="@id/product_market_price" android:text="قیمت ما" 
android:layout_alignParentLeft="true" android:layout_marginLeft="8dp"/>

<TextView android:layout_height="wrap_content" 
android:layout_width="wrap_content" android:id="@+id/product_min_amount" 
android:textColor="@color/semi_black" android:textSize="12sp" 
android:layout_below="@id/product_market_price" 
android:layout_alignParentLeft="true" android:layout_marginLeft="8dp" 
android:visibility="gone"/>

<TextView android:layout_height="wrap_content" 
android:layout_width="wrap_content" android:id="@+id/product_image_url" 
android:textColor="@color/semi_black" android:textSize="12sp" 
android:layout_below="@id/product_market_price" 
android:layout_alignParentLeft="true" android:layout_marginLeft="8dp" 
android:visibility="gone"/>

</RelativeLayout>

<RelativeLayout android:layout_height="wrap_content" 
android:layout_width="0dp" android:layout_weight="1" 
android:visibility="gone"> </RelativeLayout>

</LinearLayout>

final result will be something like this...(this is something similar,not exactly what xml file is)

enter image description here

categories are outer RecyclerView and fruits are inner RecyclerView

ask me if you have problem implementating this...

Salar Arabpour
  • 435
  • 2
  • 9
  • Fantastic! I got it working on android studio. Just one question: How do you make the categories wrap the product list on the left instead of as a header? I was able to make the inner recyclerview vertical and am now trying to center the category titles both vertically and horizontally to the left of the product list – Bread Feb 16 '20 at 20:13
  • 1
    easiest way would be wrapping title TextView in a RelativeLayout. TextView with xml attribute android:centerVertical="true" – Salar Arabpour Feb 16 '20 at 22:19
  • May I please see your xml layouts? – Bread Feb 16 '20 at 23:30
  • 1
    i have added xml layouts too,but remember that screenshot is something similar and not exactly what xml code is,i just could'nt build project and found a similar screenshot from website of that customer – Salar Arabpour Feb 17 '20 at 05:15
  • Thank you! I marked your solution as the answer. Just one last question: how do I edit the data in the inner adapter through the outer adapter? Like lets say when I click on the mango, I want the mango visibility to be `GONE`. How do I do that? Thank you for your time!! – Bread Feb 17 '20 at 23:28
  • 1
    thank you Bread,you can do that in on click of inner adapter.look at this example...holder.btnAction.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { list.remove(position); notifyDataSetChanged(); } }); – Salar Arabpour Feb 18 '20 at 05:13
  • Very good and easy explanation. Thanks – Saify May 14 '22 at 08:28
  • what about saving scroll state of inner adapter? – AlexS Jan 17 '23 at 06:22