Android: 如何在 CardView 中插入 RecyclerView?

Android: how can I insert a RecyclerView inside CardView?

我说的 activity 必须显示一个由 CardViews 填充的 RecyclerView 作为项目。我的目标是在每个 CardView 中依次显示一个 RecyclerView。

这是我的 Activity 的基本 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>

这是我的 CardView 的 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>

所以,我大胆地做了我的第一次尝试,实现了两个 RecyclerView.Adapters,一个用于(让我们称之为)"main" RecyclerView,一个用于每个 CardView 中的单个:

下面是两段代码:

"Main" RecyclerView(带 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(带 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);
        }
    }
}

如您所见,我认为在第一个适配器中实例化第二个适配器是正确的,并且为每个项目的 RecyclerView 附加一个新的 LayoutManager 并设置第二个适配器。但是正如您所看到的,我的 "main" Rec.View 的前两项不包含另一个 Rec.View 工作得很好,但其他的则没有。

我该如何解决这个问题?拜托,我没主意了。

我遇到了完全相同的问题。您必须在 CardView 中指定 RecyclerView 的布局高度。将其从 wrap_content 更改为 dp 中的特定值。如果父滚动是垂直的,嵌套的 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="100dp"
        android:paddingTop="5dp"
        android:paddingLeft="@dimen/activity_horizontal_margin" >

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

从支持库 23.2 开始,LayoutManager API 带来了自动测量功能,允许 RecyclerView 根据其内容的大小调整自身的大小。这意味着现在可以使用 WRAP_CONTENT 作为 RecyclerView 的一个维度。您会发现所有内置的布局管理器现在都支持自动测量。

Source