如何在RecyclerView中显示CardView(具有不同的内容类型)

时间:2018-09-02 22:09:44

标签: java android xml android-recyclerview android-cardview

我正在尝试显示另外一个CardView,它包含不同的布局,但是我的代码迷路了。我也不确定如何在CardView本身的GridView中显示字符串数组。有谁知道我可能在哪里出了问题以及该怎么做才能实现以下目标?

  1. 将包含GridView的CardView放在RecyclerView中的任意位置。
  2. 在CardView的GridView中显示字符串数组

我想添加到RecyclerView中的内容(在 Item A CardView上方)

enter image description here

回收者查看当前内容

enter image description here

片段类

public class MyFragment extends android.support.v4.app.Fragment {

    private MonRecyclerAdapterWithGrid adapterG;

    static final String[] frenchVowels = new String[]{
            "a", "e", "i", "o", "u", "y"
    };


    public MyFragment() {}

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        return inflater.inflate(R.layout.fragment_rv, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        View v = getView();
        assert v != null;

        recyclerView = v.findViewById(R.id.my_recyclerview);
        linearLayoutManager = new LinearLayoutManager(getActivity());

        MyRecyclerAdapter adapter = new MyRecyclerAdapter(getContext(), getHeader(), getListItemsG(), getListItemsT());
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(adapter);

        super.onActivityCreated(savedInstanceState);
    }

    RecyclerView recyclerView;
    LinearLayoutManager linearLayoutManager;

    public RecyclerViewHeader getHeader()
    {
        return new RecyclerViewHeader();
    }

    public List<RecyclerViewItemGV> getListItemsG() {
        List<RecyclerViewItemGV> rvItemsG = new ArrayList<>();

        RecyclerViewItemGV itemG = new RecyclerViewItemGV();
        itemG.setTitleGV("Item A");
        itemG.setVowelsGV(adapterG);
        for (String fVowels : frenchVowels) {
            // ?????? Still not working :-(
            adapterG.addAdapterItem(new MyFragment.AdapterItem(frenchVowels));
        }
        rvItemsG.add(itemG);

        return rvItemsG;
    }

        public List<RecyclerViewItemTV> getListItemsT()
    {
        List<RecyclerViewItemTV> rvItemsT = new ArrayList<>();

        RecyclerViewItemTV itemA = new RecyclerViewItemTV();
        itemA.setTitleTV("Item A");
        itemA.setDescriptionTV("Feature A1");
        rvItemsT.add(itemA);

        RecyclerViewItemTV itemB = new RecyclerViewItemTV();
        itemB.setTitleTV("Item B");
        itemB.setDescriptionTV("Feature B1\nFeature B2");
        rvItemsT.add(itemB);

        RecyclerViewItemTV itemC = new RecyclerViewItemTV();
        itemC.setTitleTV("Item C");
        itemC.setDescriptionTV("Feature C1\nFeature C2\nFeature C3");
        rvItemsT.add(itemC);

        return rvItemsT;
    }
}

RecyclerView适配器类

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

    private static final int TYPE_HEADER = 0;
    private static final int TYPE_ITEMG = 1;
    private static final int TYPE_ITEMT = 2;

    private Context mContext;

    RecyclerViewHeader header;
    List<RecyclerViewItemGV> listItemsG;
    List<RecyclerViewItemTV> listItemsT;
    ValueAnimator mAnimator;



    public MyRecyclerAdapter(Context context, RecyclerViewHeader header, List<RecyclerViewItemGV> listItemsG, List<RecyclerViewItemTV> listItemsT)
    {
        this.mContext = context;
        this.header = header;
        this.listItemsG = listItemsG;
        this.listItemsT = listItemsT;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(viewType == TYPE_HEADER)
        {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_header_expandcollapsebuttons, parent, false);
            return new MyRecyclerAdapter.VHHeader(v);
        }
        else if(viewType == TYPE_ITEMG)
        {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item_gv, parent, false);
            return new MyRecyclerAdapter.VHItemG(v);
        }
        else if(viewType == TYPE_ITEMT)
        {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item_tv, parent, false);
            return new MyRecyclerAdapter.VHItemT(v);
        }
        throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
    }

    private RecyclerViewItemGV getItemG(int position)
    {
        return listItemsG.get(position);
    }

    private RecyclerViewItemTV getItemT(int position)
    {
        return listItemsT.get(position);
    }


    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        final Typeface iconFont = FontManager.getTypeface(mContext, FontManager.FONTAWESOME);

        if (holder instanceof MyRecyclerAdapter.VHHeader)
        {
            final MyRecyclerAdapter.VHHeader vhHeader = (MyRecyclerAdapter.VHHeader)holder;
        }
        else if (holder instanceof MyRecyclerAdapter.VHItemG){
            RecyclerViewItemGV currentItemG = getItemG(position-1);
            final MonRecyclerAdapterWithGrid.VHItemG vhItemG = (MyRecyclerAdapter.VHItemG)holder;

            vhItemG.txtAG.setText(currentItemG.getTitleGV());

            vhItemG.mGridViewG.setVisibility(View.GONE);


            vhItemG.txtExpandCollapseG.setText(R.string.fa_icon_chevron_down);
            vhItemG.txtExpandCollapseG.setTypeface(iconFont);

            //Add onPreDrawListener
            vhItemG.mGridViewG.getViewTreeObserver().addOnPreDrawListener(
                    new ViewTreeObserver.OnPreDrawListener() {

                        @Override
                        public boolean onPreDraw() {
                            vhItemG.mGridViewG.getViewTreeObserver().removeOnPreDrawListener(this);
                            vhItemG.mGridViewG.setVisibility(View.GONE);

                            final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                            final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                            vhItemG.mGridViewG.measure(widthSpec, heightSpec);

                            vhItemG.mGridViewHeight = vhItemG.mGridViewG.getMeasuredHeight();

                            return true;
                        }
                    });

            vhItemG.mCardViewG.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(vhItemG.mGridViewG.getVisibility() == View.GONE){
                        vhItemG.expandG();
                    } else {
                        vhItemG.collapseG();
                    }
                }
            });
        }
        else if (holder instanceof MyRecyclerAdapter.VHItemT)
        {
            RecyclerViewItemTV currentItem = getItemT(position-2);
            final MyRecyclerAdapter.VHItemT vhItemT = (MyRecyclerAdapter.VHItemT)holder;

            vhItemT.txtA.setText(currentItem.getTitleTV());
            vhItemT.txtB.setText(currentItem.getDescriptionTV());

            vhItemT.txtB.setVisibility(View.GONE);

            vhItemT.txtExpandCollapse.setText(R.string.fa_icon_chevron_down);
            vhItemT.txtExpandCollapse.setTypeface(iconFont);

            //Add onPreDrawListener
            vhItemT.txtB.getViewTreeObserver().addOnPreDrawListener(
                    new ViewTreeObserver.OnPreDrawListener() {

                        @Override
                        public boolean onPreDraw() {
                            vhItemT.txtB.getViewTreeObserver().removeOnPreDrawListener(this);
                            vhItemT.txtB.setVisibility(View.GONE);

                            final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                            final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                            vhItemT.txtB.measure(widthSpec, heightSpec);

                            vhItemT.textBHeight = vhItemT.txtB.getMeasuredHeight();

                            return true;
                        }
                    });

            vhItemT.cardView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(vhItemT.txtB.getVisibility() == View.GONE){
                        vhItemT.expandT();
                    } else {
                        vhItemT.collapseT();
                    }
                }
            });
        }
    }

    // need to override this method
    @Override
    public int getItemViewType(int position) {
        if(isPositionHeader(position))
        return TYPE_HEADER;
        return TYPE_ITEMG;
        return TYPE_ITEMT;
    }

    private boolean isPositionHeader(int position)
    {
        return position == 0;
    }

    @Override
    public int getItemCount() {
        return listItemsG.size()+1;
        return listItemsT.size()+1;
    }

    class VHHeader extends RecyclerView.ViewHolder{
        Button btnCollapseAll, btnExpandAll;

        public VHHeader(View headerView) {
            super(headerView);

            this.btnCollapseAll = headerView.findViewById(R.id.btn_collapseall);
            this.btnExpandAll = headerView.findViewById(R.id.btn_expandall);
        }
    }

    public class VHItemG extends RecyclerView.ViewHolder{
        CardView mCardViewG;
        LinearLayout mLinearLayoutG;
        RelativeLayout mRelativeLayoutG;
        RecyclerView mRecyclerViewG;
        GridView mGridViewG;
        TextView txtExpandCollapseG, txtAG;
        public int mGridViewHeight;


        public VHItemG(View itemView) {
            super(itemView);

            this.mCardViewG = itemView.findViewById(R.id.cv_gv);
            this.mLinearLayoutG = itemView.findViewById(R.id.linearlayout_gv_titlerow);
            this.mRelativeLayoutG = itemView.findViewById(R.id.relativelayout_gv);
            this.mRecyclerViewG = itemView.findViewById(R.id.my_recyclerview);
            this.txtAG = itemView.findViewById(R.id.tv_gv_A);
            this.txtExpandCollapseG = itemView.findViewById(R.id.tv_gv_expandcollapse);
            this.mGridViewG = itemView.findViewById(R.id.gv_a);
        }

        private void expandG() {
            // change visibility to 'VISIBLE'
            mGridViewG.setVisibility(View.VISIBLE);

            // change direction of chevron to 'up'
            txtExpandCollapseG.setText(R.string.fa_icon_chevron_up);

            // apply animation to the height of 'txtB'
            mAnimator = slideAnimator(0, mGridViewHeight);

            // start the animation
            mAnimator.start();
        }

        private void collapseG() {
            // change direction of chevron to 'down'
            txtExpandCollapseG.setText(R.string.fa_icon_chevron_down);

            int finalHeight = mGridViewG.getHeight();

            ValueAnimator mAnimator = slideAnimator(finalHeight, 0);

            mAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationEnd(Animator animator) {
                    // Height will be 0, but set visibility to 'GONE'
                    mGridViewG.setVisibility(View.GONE);
                }

                @Override
                public void onAnimationStart(Animator animator) {
                }

                @Override
                public void onAnimationCancel(Animator animator) {
                }

                @Override
                public void onAnimationRepeat(Animator animator) {
                }
            });
            mAnimator.start();
        }


        public ValueAnimator slideAnimator(int start, int end) {

            ValueAnimator animator = ValueAnimator.ofInt(start, end);


            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    // update height
                    int value = (Integer) valueAnimator.getAnimatedValue();

                    ViewGroup.LayoutParams layoutParams = mGridViewG.getLayoutParams();
                    layoutParams.height = value;
                    mGridViewG.setLayoutParams(layoutParams);
                }
            });
            return animator;
        }
    }

    public class VHItemT extends RecyclerView.ViewHolder{
        CardView cardView;
        LinearLayout mLinearLayout;
        RecyclerView mRecyclerView;
        RelativeLayout mRelativeLayout;
        TextView txtExpandCollapse, txtA, txtB;
        public int textBHeight;

        public VHItemT(View itemView) {
            super(itemView);

            this.cardView = itemView.findViewById(R.id.linearlayout_tv_main);
            this.mLinearLayout = itemView.findViewById(R.id.linearlayout_tv_titlerow);
            this.mRelativeLayout = itemView.findViewById(R.id.relativelayout_tv);
            this.mRecyclerView = itemView.findViewById(R.id.my_recyclerview);
            this.txtExpandCollapse = itemView.findViewById(R.id.tv_tv_expandcollapse);
            this.txtA = itemView.findViewById(R.id.tv_tv_A);
            this.txtB = itemView.findViewById(R.id.tv_tv_B);
        }

        private void expandT() {
            // change visibility to 'VISIBLE'
            txtB.setVisibility(View.VISIBLE);

            // change direction of chevron to 'up'
            txtExpandCollapse.setText(R.string.fa_icon_chevron_up);

            // apply animation to the height of 'txtB'
            mAnimator = slideAnimator(0, textBHeight);

            // start the animation
            mAnimator.start();
        }

        private void collapseT() {
            // change direction of chevron to 'down'
            txtExpandCollapse.setText(R.string.fa_icon_chevron_down);

            int finalHeight = txtB.getHeight();

            ValueAnimator mAnimator = slideAnimator(finalHeight, 0);

            mAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationEnd(Animator animator) {
                    // Height will be 0, but set visibility to 'GONE'
                    txtB.setVisibility(View.GONE);
                }

                @Override
                public void onAnimationStart(Animator animator) {
                }

                @Override
                public void onAnimationCancel(Animator animator) {
                }

                @Override
                public void onAnimationRepeat(Animator animator) {
                }
            });
            mAnimator.start();
        }


        public ValueAnimator slideAnimator(int start, int end) {

            ValueAnimator animator = ValueAnimator.ofInt(start, end);


            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    // update height
                    int value = (Integer) valueAnimator.getAnimatedValue();

                    ViewGroup.LayoutParams layoutParams = txtB.getLayoutParams();
                    layoutParams.height = value;
                    txtB.setLayoutParams(layoutParams);
                }
            });
            return animator;
        }
    }
}

GridView适配器(当前不包含在项目中)

   private class MyGVAdapter extends ArrayAdapter<AdapterItem> {
        private List<AdapterItem> items = new ArrayList<>();

        MyGVAdapter(Context context, int textviewid) {
            super(context, textviewid);
        }

        void addAdapterItem(MyGVFragment.AdapterItem item) {
            items.add(item);
        }

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

        @Override
        public MyGVFragment.AdapterItem getItem(int position) {
            return ((null != items) ? items.get(position) : null);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @NonNull
        @Override
        public View getView(final int position, View convertView, @NonNull final ViewGroup parent) {
            View rowView;
            if (convertView == null) {
                rowView = getActivity().getLayoutInflater().inflate(R.layout.gridview_item, parent, false);
            } else {
                rowView = convertView;
            }

            TextView tv = rowView.findViewById(R.id.item_gridview);
            tv.setText(items.get(position).first);

            return rowView;
        }
    }

    class AdapterItem {
        String first;

        AdapterItem(String first) {
            this.first = first;
        }
    }
}

gridview_item.xml

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

    <TextView
        android:id="@+id/item_gridview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingStart="0dp"
        android:paddingEnd="10dp"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="?android:attr/textColorPrimary"
        />
</LinearLayout>

具有GridView的CardView(recyclerview_item_gv)

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:focusable="true"
    android:id="@+id/cv_gv"
    android:layout_marginBottom="20dp"
    >

    <LinearLayout
        android:id="@+id/lineralayout_gv_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="10dp"
        android:animateLayoutChanges="true">

        <LinearLayout
            android:id="@+id/linearlayout_gv_titlerow"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_marginBottom="2dp"
            android:weightSum="100">

            <TextView
                android:id="@+id/tv_gv_A"
                android:layout_weight="90"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Medium" />

            <TextView
                android:id="@+id/tv_gv_expandcollapse"
                android:importantForAccessibility="no"
                android:clickable="true"
                android:focusable="true"
                android:layout_weight="10"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Large" />
        </LinearLayout>

        <RelativeLayout
            android:id="@+id/relativelayout_gv"
            android:animateLayoutChanges="true"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <GridView
                android:id="@+id/gv_a"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:columnWidth="100dp"
                android:numColumns="auto_fit"
                android:layout_marginBottom="20dp"
                android:stretchMode="columnWidth" />
        </RelativeLayout>

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

具有TextView的CardView(recyclerview_item_tv.xml)

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:focusable="true"
    android:id="@+id/cv_tv"
    android:layout_marginBottom="20dp">

    <LinearLayout
        android:id="@+id/linearlayout_gv_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="10dp"
        android:animateLayoutChanges="true">

        <LinearLayout
            android:id="@+id/linearlayout_tv_titlerow"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_marginBottom="2dp"
            android:weightSum="100">

            <TextView
                android:id="@+id/tv_tv_A"
                android:layout_weight="90"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Medium" />

            <TextView
                android:id="@+id/tv_tv_expandcollapse"
                android:importantForAccessibility="no"
                android:clickable="true"
                android:focusable="true"
                android:layout_weight="10"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Large" />
        </LinearLayout>

        <RelativeLayout
            android:id="@+id/relativelayout_tv"
            android:animateLayoutChanges="true"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/tv_B"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Large" />
        </RelativeLayout>

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

1 个答案:

答案 0 :(得分:2)

好的,所以我举了一个简单的例子。这就是我发布的Activity类的样子,所有项目都在同一RecyclerView中:

recyclerview snapshot

请记住,它可能看起来不像您的代码,因为我试图使用(至少对我来说)最佳实践,并且通过在同一个类中包含很多内容来缩短代码和类的数量。< / p>

这里是活动:

public class RecyclerActivity extends AppCompatActivity {

RecyclerView recycler;
ArrayList<String> data;
RecyclerView.Adapter<ViewHolder> adapter;
private static final int ITEM_TYPE = 100;
private static final int HEADER_TYPE = 101;
private static final int HEADER_TYPE_2 = 102;
private static final int GRID_TYPE = 103;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recycler);

    // find recycler,
    recycler = findViewById(R.id.recycler);
    // set the layout
    recycler.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));

    // init data,
    data = new ArrayList<>();
    data.add("Item A");
    data.add("Item B");
    data.add("Item C");

    // create the adapter
    adapter = createAdapter();

    // set the adapter
    recycler.setAdapter(adapter);
}

// creates the adapter,
private RecyclerView.Adapter<ViewHolder> createAdapter() {
    return new RecyclerView.Adapter<ViewHolder>() {
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int type) {
            switch (type) {
                case HEADER_TYPE:
                    // inflate the layout,
                    ViewHolder holderHeader1 = new ViewHolder(inflateHelper(R.layout.header, parent));
                    // set an on click to the view here to create only one object,
                    holderHeader1.itemView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            // do something
                        }
                    });
                    return holderHeader1;
                case HEADER_TYPE_2:
                    // inflate the layout,
                    ViewHolder holderHeader2 = new ViewHolder(inflateHelper(R.layout.header, parent));
                    // set an on click to the view here to create only one object,
                    holderHeader2.itemView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            // do something
                        }
                    });
                    return holderHeader2;
                case ITEM_TYPE:
                    // inflate the layout,
                    ViewHolder holderItem = new ViewHolder(inflateHelper(R.layout.item, parent));
                    // set an on click to the view here to create only one object,
                    holderItem.itemView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            // do something
                        }
                    });
                    return holderItem;
                case GRID_TYPE:
                    // inflate the layout,
                    ViewHolder holderGrid = new ViewHolder(inflateHelper(R.layout.grid, parent));
                    // set an on click to the view here to create only one object,
                    holderGrid.itemView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            // do something
                        }
                    });
                    return holderGrid;
                    default:
                        // inflate the layout,
                        ViewHolder holderItemDefault = new ViewHolder(inflateHelper(R.layout.item, parent));
                        // set an on click to the view here to create only one object,
                        holderItemDefault.itemView.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                // do something
                            }
                        });
                        return holderItemDefault;
            }
        }

        /**
         * Keep the viewholder simple and the all the view finding here. This way you
         * only have one viewholder.
         */
        @Override
        public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
            // go through the positions
            switch (getItemViewType(position)) {
                case HEADER_TYPE:
                    Button expandButton = viewHolder.itemView.findViewById(R.id.button);
                    expandButton.setText("Expand");
                    break;
                case HEADER_TYPE_2:
                    Button collapseButton = viewHolder.itemView.findViewById(R.id.button);
                    collapseButton.setText("Collapse");
                    break;
                case ITEM_TYPE:
                    // get the current item
                    String item = data.get(position - 3);
                   TextView title = viewHolder.itemView.findViewById(R.id.title);
                   title.setText(item);
                    break;
                case GRID_TYPE:
                    break;
            }
        }

        @Override
        public int getItemCount() {
            return data.size() + 3;
        }

        @Override
        public int getItemViewType(int position) {
            switch (position) {
                case 0:
                    return HEADER_TYPE;
                case 1:
                    return HEADER_TYPE_2;
                case 2:
                    return GRID_TYPE;
                default: return ITEM_TYPE;
            }
        }
    };
}

private View inflateHelper(int resId, ViewGroup parent) {
    return LayoutInflater.from(this).inflate(resId, parent, false);
}

// inner class for viewholder to use,
class ViewHolder extends RecyclerView.ViewHolder {
    public ViewHolder(@NonNull View itemView) {
        super(itemView);
    }
}
}

您可能会注意到我使用了一个ViewHolder。我认为我们应该采用这种模式,因为它大大简化了代码。您可以在onBind方法中找到所需的视图,从而避免对所有类型的视图使用一个视图。

我也将on click侦听器添加到onCreateViewHolder中,因为在此处设置它的效率要高得多,并且它允许Viewholder不是特定于onClick的。

正如我所说,您可以根据需要使用任意多种类型,只需检查一下并将其设置在正确的位置即可。

以下是您感兴趣的布局文件:

标题

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="4dp"
    android:gravity="center">

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Expand" />
</LinearLayout>

项目

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:elevation="2dp"
    android:layout_margin="16dp"
    android:background="@drawable/rounded">

<TextView
    android:id="@+id/title"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content"
    android:text="Item A"
    android:textColor="#fff"/>

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_chevron_right"
    android:tint="#fff"/>
 </LinearLayout>

网格布局(我在这里作了一点欺骗,因为我没有看到不对元音进行硬编码的原因,尽管您可能需要动态地对其进行编码)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="32dp"
    android:layout_marginEnd="32dp"
    android:layout_marginTop="16dp"
    android:layout_marginBottom="16dp"
    android:padding="16dp"
    android:background="@drawable/rounded"
    android:backgroundTint="#fff"
    android:elevation="4dp">

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

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:paddingBottom="16dp"
            android:text="French Vowels"
            android:textStyle="bold"
            style="@style/Base.TextAppearance.AppCompat.Medium"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="8dp">

            <TextView
                android:id="@+id/a"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:gravity="center"
                android:layout_height="wrap_content"
                android:text="a"
                style="@style/Base.TextAppearance.AppCompat.Medium"/>

            <TextView
                android:id="@+id/e"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:gravity="center"
                android:layout_height="wrap_content"
                android:text="e"
                style="@style/Base.TextAppearance.AppCompat.Medium"/>

            <TextView
                android:id="@+id/i"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:gravity="center"
                android:layout_height="wrap_content"
                android:text="i"
                style="@style/Base.TextAppearance.AppCompat.Medium"/>
        </LinearLayout>
        <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
            android:padding="8dp">

        <TextView
            android:id="@+id/o"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:layout_height="wrap_content"
            android:text="o"
            style="@style/Base.TextAppearance.AppCompat.Medium"/>

        <TextView
            android:id="@+id/u"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:layout_height="wrap_content"
            android:text="u"
            style="@style/Base.TextAppearance.AppCompat.Medium"/>

        <TextView
            android:id="@+id/y"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:layout_height="wrap_content"
            android:text="y"
            style="@style/Base.TextAppearance.AppCompat.Medium"/>
    </LinearLayout>
    </LinearLayout>
</FrameLayout>

圆形可绘制对象

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#222"/>
    <corners android:radius="6dp"/>
</shape>

对于任何阅读本书的人,如果您碰巧使用Kotlin,请考虑使用我的小型库,该库将此回收站视图样板简化为简单的功能链:

https://github.com/Pfuster12/BoilerCycle