Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: how can I insert a RecyclerView inside CardView?

The activity I am talking about must show a RecyclerView populated by CardViews as items. My goal is to show in every CardView a RecyclerView in its turn.

Here my Activity's basic xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ConjActivity" >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/conjCardList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="false" />

</LinearLayout>

And here is the layout of my CardView's RecyclerView:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/card_analysis"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/activity_vertical_margin"
    android:layout_marginBottom="@dimen/activity_vertical_margin" 
    android:layout_marginLeft="@dimen/activity_horizontal_margin"
    android:layout_marginRight="@dimen/activity_horizontal_margin"
    android:padding="5dp"
    card_view:cardCornerRadius="5dp" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <android.support.v7.widget.RecyclerView
            android:id="@+id/item_mode"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="5dp"
            android:paddingLeft="@dimen/activity_horizontal_margin" >

        </android.support.v7.widget.RecyclerView>
    </LinearLayout>
</android.support.v7.widget.CardView>

So, I boldly made my first attempt by implementing two RecyclerView.Adapters, one for the (let's call it) "main" RecyclerView and one for the single ones in every CardView:

Here are the two pieces of code:

"Main" RecyclerView (w/ ViewHolders):

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

    private static Context context;
    private LinearLayoutManager llm;
    private static ConjFormAdapter formAdapt;
    private ArrayList<String> adapterList;
    private List<Object> items;
    private static final int
            HEADER = 0,
            CONJTYPE = 1,
            ITEM = 2;
    private Paradigma par;
    private String sel_vb;

    public ConjCardAdapter(List<Object> items){
        this.items = items;
        context = ConjActivity.context;
        adapterList = new ArrayList<String>();
        formAdapt = new ConjFormAdapter(adapterList);
    }

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType){

        switch(viewType){
        case HEADER:
            return new HeaderHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_header, viewGroup, false));
        case CONJTYPE:
            return new ConjTypeHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_conjtext, viewGroup, false));
        case ITEM:
            return new ItemModeHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_item, viewGroup, false));
        default:
            return null;
        }
    }

    public void onBindViewHolder(RecyclerView.ViewHolder vvh, final int pos) {
        HeaderItem headerItem;
        String stringItem;
        ArrayList<String> listItem;
        HeaderHolder hh;
        ConjTypeHolder cjh;
        ItemModeHolder imh;

        switch(getItemViewType(pos)){
        case HEADER:
            // it doesn't really matter...
            break;
        case CONJTYPE:
            // it doesn't really matter...
            break;
        case ITEM:
            listItem = (ArrayList<String>) items.get(pos);
            imh = (ItemModeHolder) vvh;
            llm = new LinearLayoutManager(context);
            imh.rv_mode.setLayoutManager(llm);
            adapterList.addAll(listItem);
            imh.rv_mode.setAdapter(formAdapt);
            formAdapt.notifyDataSetChanged();
            break;
        }           
    }

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

    @Override
    public int getItemViewType(int position) {

        switch(position){
        case 0:
            return HEADER;
        case 1:
            return CONJTYPE;
        default:
            return ITEM;
        }
    }


    static class HeaderHolder extends RecyclerView.ViewHolder{

        TextView verbo,
                paradigma,
                analisi;
        View divider;

        public HeaderHolder(View itemView) {
            super(itemView);
            verbo = (TextView) itemView.findViewById(R.id.verb);
            paradigma = (TextView) itemView.findViewById(R.id.paradigm);
            analisi = (TextView) itemView.findViewById(R.id.analysis);
            divider = (View) itemView.findViewById(R.id.divider);
        }
    }

    static class ConjTypeHolder extends RecyclerView.ViewHolder{

        TextView type;

        public ConjTypeHolder(View itemView) {
            super(itemView);
            type = (TextView) itemView.findViewById(R.id.conj_type);
        }
    }
:
    static class ItemModeHolder extends RecyclerView.ViewHolder{

        RecyclerView rv_mode;

        public ItemModeHolder(View itemView) {
            super(itemView);
            rv_mode = (RecyclerView) itemView.findViewById(R.id.item_mode);
        }
    }

}

Items' RecyclerView (w/ ViewHolder):

public class ConjFormAdapter extends RecyclerView.Adapter<ConjFormAdapter.FormHolder>{

    private Context context;
    private ArrayList<String> list;
    private Paradigma par;
    private String sel_vb;
    private ArrayList<Long> ids;
    private HashMap<String, Long> mIdMap;
    private StringAnalisi analisi;
    private final int IND_MODE_TYPE=0,
            ELSE_MODE_TYPE=1,
            TENSE_TYPE=2,
            FORM_TYPE=3;

    public ConjFormAdapter(ArrayList<String> list){
        this.list = list;
        // Constructor implementation
    }

    // other methods

    @Override
    public FormHolder onCreateViewHolder(ViewGroup viewGroup, int itemType) {
        switch(itemType){
        case IND_MODE_TYPE:
            return new FormHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_mode_ind, viewGroup, false));
        case ELSE_MODE_TYPE:
            return new FormHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_mode_else, viewGroup, false));
        case TENSE_TYPE:
            return new FormHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_tense, viewGroup, false));
        default:
            return new FormHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_form, viewGroup, false));
        }
    }

    @Override
    public void onBindViewHolder(FormHolder fh, int pos) {

        fh.txt.setText(list.get(pos));

        // other implementation

    }

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

    @Override
    public int getItemViewType(int position) {
        String item = (String) list.get(position);
        if(item.equals(context.getResources().getString(R.string.ind))){
            return IND_MODE_TYPE;
        } else if(item.equals(context.getResources().getString(R.string.subj))||item.equals(context.getResources().getString(R.string.imp))||item.equals(context.getResources().getString(R.string.inf))||item.equals(context.getResources().getString(R.string.pt))||item.equals(context.getResources().getString(R.string.ger))||item.equals(context.getResources().getString(R.string.gerv))||item.equals(context.getResources().getString(R.string.sup))){
            return ELSE_MODE_TYPE;
        } else if(item.equals(context.getResources().getString(R.string.pres))||item.equals(context.getResources().getString(R.string.impf))||item.equals(context.getResources().getString(R.string.fut))||item.equals(context.getResources().getString(R.string.pf))||item.equals(context.getResources().getString(R.string.ppf))||item.equals(context.getResources().getString(R.string.futant))){
            return TENSE_TYPE;
        } else {
            return FORM_TYPE;
        }
    }

    @Override
    public long getItemId(int position) {

        String item = list.get(position);
        return mIdMap.get(item);
    }

    @Override
    public void setHasStableIds(boolean hasStableIds) {
        super.setHasStableIds(true);
    }


    static class FormHolder extends RecyclerView.ViewHolder{

        TextView txt;
        View divider1, divider2, divider3;

        public FormHolder(View itemView) {
            super(itemView);
            txt = (TextView) itemView.findViewById(R.id.text1);
            divider1 = (View) itemView.findViewById(R.id.conj_divider1);
            divider2 = (View) itemView.findViewById(R.id.conj_divider2);
            divider3 = (View) itemView.findViewById(R.id.conj_divider3);
        }
    }
}

As you can see I thought it was right to instantiate the second adapter in the first one, and for every item's RecyclerView to attach a new LayoutManager and to set the second adapter. But as you can see the first two items of my "main" Rec.View which don't contain another Rec.View work just fine, but the others don't.

The items with a RecyclerView don't show up like they should

How can I solve the issue? Please, I am out of ideas.

like image 711
Massimo Baldrighi Avatar asked Jan 27 '15 09:01

Massimo Baldrighi


People also ask

Can we use RecyclerView inside RecyclerView in Android?

We can use a RecyclerView inside another RecyclerView. We refer to this as nested RecyclerView. It is an instance where one RecyclerView widget is the parent to another RecyclerView widget. A good example where a nested RecyclerView widget is implemented includes the Google Play Store.

Can we use nested RecyclerView in Android?

A nested RecyclerView is an implementation of a RecyclerView within a RecyclerView. An example of such a layout can be seen in a variety of apps such as the Play store where the outer (parent) RecyclerView is of Vertical orientation whereas the inner (child) RecyclerViews are of horizontal orientations.

Can I put RecyclerView in fragment?

Alternatively, we can also use Palette in Android Studio to create RecyclerView: Drag RecyclerView from Palette to Layout in fragment_second. xml (using Design view).


2 Answers

As of support library 23.2, the LayoutManager API brings auto-measurement which allows a RecyclerView to size itself based on the size of its contents. This means that using WRAP_CONTENT for a dimension of the RecyclerView, are now possible. You’ll find all built in LayoutManagers now support auto-measurement.

Source

like image 26
Neel Avatar answered Oct 04 '22 16:10

Neel


I faced the exact same problem. You have to specify the layout height of the RecyclerView inside the CardView. Change it from wrap_content to a specific value in dp. Nested RecyclerView doesnt wrap the content in its height if the parent scrolling is VERTICAL and similarly doesnt wrap the content in its width when the parent scrolling is HORIZONTAL.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/card_analysis"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginBottom="@dimen/activity_vertical_margin" 
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:padding="5dp"
card_view:cardCornerRadius="5dp" >

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/item_mode"
        android:layout_width="wrap_content"
        android:layout_height="100dp"
        android:paddingTop="5dp"
        android:paddingLeft="@dimen/activity_horizontal_margin" >

    </android.support.v7.widget.RecyclerView>
</LinearLayout>
</android.support.v7.widget.CardView>
like image 51
Ashish Kushwaha Avatar answered Oct 04 '22 16:10

Ashish Kushwaha