web-dev-qa-db-fra.com

Android: comment insérer un RecyclerView dans CardView?

L'activité dont je parle doit afficher un RecyclerView rempli par CardViews en tant qu'éléments. Mon objectif est de montrer dans chaque CardView une RecyclerView à son tour.

Voici le xml de base de mon activité:

<?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>

Et voici la disposition du RecyclerView de mon CardView:

<?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>

Donc, j'ai hardiment fait ma première tentative en implémentant deux RecyclerView.Adapters, un pour le (appelons-le) RecyclerView "principal" et un pour les simples dans chaque CardView:

Voici les deux morceaux de code:

RecyclerView "principal" (avec 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);
        }
    }

}

RecyclerView des articles (avec 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);
        }
    }
}

Comme vous pouvez le voir, j'ai pensé qu'il était juste d'instancier le deuxième adaptateur dans le premier, et pour chaque élément RecyclerView d'attacher un nouveau LayoutManager et de définir le deuxième adaptateur. Mais comme vous pouvez le voir, les deux premiers éléments de ma Rec.View "principale" qui ne contiennent pas d'autre Rec.View fonctionnent très bien, mais pas les autres.

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

Comment puis-je résoudre le problème? S'il vous plaît, je suis à court d'idées.

15
Massimo Baldrighi

J'ai fait face exactement au même problème. Vous devez spécifier la hauteur de disposition du RecyclerView à l'intérieur du CardView. Remplacez-le par wrap_content par une valeur spécifique dans dp. Nested RecyclerView n'encapsule pas le contenu à sa hauteur si le défilement parent est VERTICAL et de la même manière n'encapsule pas le contenu dans sa largeur lorsque le défilement parent est 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>
16
Ashish Kushwaha

Depuis la bibliothèque de support 23.2, l'API LayoutManager apporte une mesure automatique qui permet à RecyclerView de se dimensionner en fonction de la taille de son contenu. Cela signifie que l'utilisation de WRAP_CONTENT pour une dimension de RecyclerView est désormais possible. Vous constaterez que tous les LayoutManagers intégrés prennent désormais en charge la mesure automatique.

Source

7
Neel