12

L'attività di cui sto parlando deve mostrare un RecyclerView compilato da CardViews come articoli. Il mio obiettivo è mostrare in ogni CardView un RecyclerView a sua volta.Android: come posso inserire un RecyclerView all'interno di CardView?

Qui il mio xml base di attività:

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

E qui è il layout del RecyclerView di mio 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> 

Così, ho coraggiosamente fatto il mio primo tentativo mediante l'attuazione di due RecyclerView.Adapters , uno per (chiamiamolo) "principale" RecyclerView e uno per i singoli in ogni CardView:

Qui ci sono ha due pezzi di codice:

"Main" RecyclerView (w/ViewHolders): RecyclerView

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); 
     } 
    } 

} 

Articoli (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); 
     } 
    } 
} 

Come potete vedere ho pensato che Era giusto istanziare il secondo adattatore nel primo, e per RecyclerView di ogni articolo attaccare un nuovo LayoutManager e impostare il secondo adattatore. Ma come puoi vedere i primi due elementi del mio "principale" Rec.View che non contengono un altro Rec.View funzionano bene, ma gli altri no.

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

Come posso risolvere il problema? Per favore, sono fuori di idee.

risposta

16

Ho affrontato lo stesso identico problema. Devi specificare l'altezza del layout di RecyclerView all'interno del CardView. Passalo da wrap_content a un valore specifico in dp. Nested RecyclerView non avvolge il contenuto nella sua altezza se lo scorrimento genitore è VERTICALE e allo stesso modo non avvolge il contenuto nella sua larghezza quando lo scorrimento genitore è ORIZZONTALE.

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

Ma cosa succede se la mia vista riciclatore ha contenuto variabile? C'è un modo per rendere automatica la scelta dell'altezza in base al numero di articoli? –

+0

Una soluzione può essere quella di utilizzare diversi layout per il CardView contenente RecylerViews di diverse altezze e utilizzare switch case (o istruzioni condizionali) per implementarli rispettivamente. –

+1

Grazie ai tuoi suggerimenti ho finalmente risolto il problema e, se sei interessato, la soluzione alla mia seconda domanda è stata portata da @DenisNek a http://stackoverflow.com/questions/26649406/nested-recycler-view-height -doesnt-wrap-its-content/27616854 # 27616854 –

5

Al libreria di supporto 23.2, l'API LayoutManager porta automatica di misura che permette un RecyclerView per il ridimensionamento in base alle dimensioni del suo contenuto. Ciò significa che ora è possibile utilizzare WRAP_CONTENT per una dimensione di RecyclerView. Troverete tutti i layoutManager ora supportano la misurazione automatica.

Source

Problemi correlati