RecyclerView多个布局视图在一个适配器类中

这是我所取得的成就? 3个不同的部分 ,每个部分10个不同的项目

这里是我下面的教程 链接 ,下面是屏幕截图

在这里输入图像说明

试图为每个部分显示different Views喜欢:

对于第1部分 (layout_1.xml

对于第2部分 (layout_2.xml)

对于第3节 (layout_3.xml)

但是在每个Section中 显示 layout_1.xml布局视图 …(第1,2,3节)

我可以知道我在代码中的错误,我错过了什么?

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private ArrayList<SingleItemModel> itemsList; private Context mContext; public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList) { this.itemsList = itemsList; this.mContext = context; } @Override public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) { switch (i) { case 0: View viewONE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_1, null, false); SingleItemRowHolder rowONE = new SingleItemRowHolder(viewONE); return rowONE; case 1: View viewTWO = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_2, null, false); SingleItemRowHolder rowTWO = new SingleItemRowHolder(viewTWO); return rowTWO; case 2: View viewTHREE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_3, null, false); SingleItemRowHolder rowTHREE = new SingleItemRowHolder(viewTHREE); return rowTHREE; } return null; } @Override public void onBindViewHolder(SingleItemRowHolder holder, int i) { SingleItemModel singleItem = itemsList.get(i); holder.tvTitle.setText(singleItem.getName()); } @Override public int getItemCount() { return (null != itemsList ? itemsList.size() : 0); } public class SingleItemRowHolder extends RecyclerView.ViewHolder { protected TextView tvTitle; protected ImageView itemImage; public SingleItemRowHolder(View view) { super(view); this.tvTitle = (TextView) view.findViewById(R.id.tvTitle); this.itemImage = (ImageView) view.findViewById(R.id.itemImage); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(v.getContext(), tvTitle.getText(), Toast.LENGTH_SHORT).show(); } }); } } } 

Solutions Collecting From Web of "RecyclerView多个布局视图在一个适配器类中"

使用这个内部适配器:

  @Override public int getItemViewType(int position) { if (position == 0) { return 0; } else if(position == 1){ return 1; }else{ return 2; } } 

要根据recyclerview中的位置使用多个布局,您必须重写适配器内的getItemViewType(int position)方法:

  @Override public int getItemViewType(int position) { if(position==0) return 0; else if(position==1) return 1; else return 2; } 

如前所述,为了获得RecyclerView.Adapter类的getItemViewType方法,因为如果您在执行该方法时会看到它始终只返回0

  public int getItemViewType(int position) { return 0; } 

在这里调整你的适配器的代码,这应该可以解决你的问题。

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private static final int ITEM_TYPE_ROW_1 = 0; private static final int ITEM_TYPE_ROW_2 = 1; private static final int ITEM_TYPE_ROW_3 = 2; private ArrayList<SingleItemModel> itemsList; private Context context; public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList) { this.itemsList = itemsList; this.context = context; } @Override public int getItemViewType(int position) { switch (position) { case 0: return ITEM_TYPE_ROW_1; case 1: return ITEM_TYPE_ROW_2; case 2: return ITEM_TYPE_ROW_3; } throw new RuntimeException(String.format("unexpected position - %d", position)); } @Override public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { switch (viewType) { case ITEM_TYPE_ROW_1: View viewOne = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_1, null, false); return new SingleItemRowHolder(viewOne); case ITEM_TYPE_ROW_2: View viewTwo = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_2, null, false); return new SingleItemRowHolder(viewTwo); case ITEM_TYPE_ROW_3: View viewThree = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_3, null, false); return new SingleItemRowHolder(viewThree); } throw new RuntimeException(String.format("unexpected viewType - %d", viewType)); } @Override public void onBindViewHolder(SingleItemRowHolder holder, int i) { SingleItemModel singleItem = itemsList.get(i); holder.tvTitle.setText(singleItem.getName()); } @Override public int getItemCount() { return (null != itemsList ? itemsList.size() : 0); } class SingleItemRowHolder extends RecyclerView.ViewHolder { TextView tvTitle; ImageView itemImage; public SingleItemRowHolder(View view) { super(view); this.tvTitle = (TextView) view.findViewById(R.id.tvTitle); this.itemImage = (ImageView) view.findViewById(R.id.itemImage); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(v.getContext(), tvTitle.getText(), Toast.LENGTH_SHORT).show(); } }); } } } 

你可以用更简单的方法做到这一点。 在初始化适配器时传递任何flag

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private ArrayList<SingleItemModel> itemsList; private Context context; private int view; public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList, int layoutFlag) { this.itemsList = itemsList; this.context = context; switch(layoutFlag) { case 0: view = R.layout.layout_1; break; case 1: view = R.layout.layout_2; break; case 2: view = R.layout.layout_3; break; } } ... ... ... } 

使用此view进行布局参考。 在设置适配器的时候,你只需要告诉哪个布局被充气了。

您需要重写该方法

 int getItemViewType (int position) 

它接收行号,你需要返回行的“types”,即1 2或3。

结果将被传递给onCreateViewHolder。

FYI

RecyclerView也可以用来充气多个视图types。

  • 创build不同的持有者将是最容易的。
  • 创build不同的适配器是最佳解决方

尝试

  @Override public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) { switch (i) { case 0: View viewONE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_1, null, false); SingleItemRowHolder rowONE = new SingleItemRowHolder(viewONE); return rowONE; case 1: View viewTWO = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_2, null, false); SingleItemRowHolderTwo rowTWO = new SingleItemRowHolderTwo (viewTWO); return rowTWO; case 2: View viewTHREE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_3, null, false); SingleItemRowHolderThree rowTHREE = new SingleItemRowHolderThree(viewTHREE); return rowTHREE; } return null; } 

阅读RecyclerView也可以用来膨胀多个视图types

例如,如果你想显示这个视图列表:

types1types2types3types1types2types3

那么应该做的工作:

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private static final int ITEM_TYPE_ROW_1 = 0; private static final int ITEM_TYPE_ROW_2 = 1; private static final int ITEM_TYPE_ROW_3 = 2; private ArrayList<SingleItemModel> itemsList; private Context context; private ArrayList<Integer> viewTypes = new ArrayList<>(); public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList) { this.itemsList = itemsList; this.context = context; viewTypes.add(ITEM_TYPE_ROW_1); viewTypes.add(ITEM_TYPE_ROW_2); viewTypes.add(ITEM_TYPE_ROW_3); viewTypes.add(ITEM_TYPE_ROW_1); viewTypes.add(ITEM_TYPE_ROW_2); viewTypes.add(ITEM_TYPE_ROW_3); } @Override public int getItemViewType(int position) { return viewTypes.get(position); } @Override public int getItemCount() { return viewTypes.size(); } ....... ........ 

如果你想添加/删除行,那么可以在viewTypes数组中插入/删除viewTypes,然后调用RecyclerView notifyItemInserted或notifyItemRemoved方法,该列表将使用新的顺序和types的视图进行更新。

只需使用框架布局与您的片段,并添加这个片段在你的framelayout将添加像你想要的。 所以它也容易处理。 希望对你有帮助

是的,你需要重写getItemViewType(int position)方法,这有助于在回收站查看不同的视图。

我发布了一个示例代码,可以帮助你。

 public class TransactionHistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private final int TYPE_HEADER = 1; private final int TYPE_CHILD = 2; private final Context mContext; private final List<TransactionResultEntity> mTransactionList; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_HEADER: View headerView = LayoutInflater.from(mContext) .inflate(R.layout.row_transaction_header, parent, false); return new ParentTypeDataObjectHolder(headerView); case TYPE_CHILD: View childView = LayoutInflater.from(mContext) .inflate(R.layout.row_transaction_child, parent, false); return new ChildTypeDataObjectHolder(childView); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { case TYPE_HEADER: ParentTypeDataObjectHolder parentTypeDataObjectHolder = (ParentTypeDataObjectHolder) holder; parentTypeDataObjectHolder.headerYearMonthTv.setText(mTransactionList.get(holder.getAdapterPosition()).getRowLabel()); break; case TYPE_CHILD: ChildTypeDataObjectHolder childTypeDataObjectHolder = (ChildTypeDataObjectHolder) holder; childTypeDataObjectHolder.txnAmountTv.setText(mTransactionList.get(holder.getAdapterPosition()).getTransactionAmount()); break; } } @Override public int getItemCount() { return mTransactionList.size(); } @Override public int getItemViewType(int position) { if (mTransactionList.get(position).getDataType() == TYPE_HEADER) return TYPE_HEADER; else return TYPE_CHILD; } class ParentTypeDataObjectHolder extends RecyclerView.ViewHolder { private final TextView headerYearMonthTv; public ParentTypeDataObjectHolder(View itemView) { super(itemView); headerYearMonthTv = (TextView) itemView.findViewById(R.id.row_transaction_header_tv); } } class ChildTypeDataObjectHolder extends RecyclerView.ViewHolder { TextView txnAmountTv; public ChildTypeDataObjectHolder(View itemView) { super(itemView); txnAmountTv = (TextView) itemView.findViewById(R.id.transaction_child_txn_amount_tv); } } 

}

所有你需要做的是覆盖你的适配器中的方法getItemViewType()

你可以把它写成:

  @Override public int getItemViewType(int position) { if (position < 0) { return 0; } else if(position < 20) { return 1; } else { return 2; } } 

现在,如果您的itemsList ArrayList具有第1部分的前10项,第2部分的后10项以及第3部分的后10项,则以上逻辑起作用。

如果不是这种情况,那么你可以在你的SingleItemModel类中有一个整数字段sectionNumber ,它指定了该模型所属的段号。 现在你可以修改getItemViewType()方法

 @Override public int getItemViewType(int position) { SingleItemModel singleItemModel = itemsList.get(position); if (singleItemModel.getSection() == 1) { return 0; } else if(singleItemModel.getSection() == 2) { return 1; } else { return 2; } } 

好的,如果我没有弄错,你想制作第二个适配器,提供行列表,variables,所以它支持不同的布局,不是基于它的位置,而是来自主适配器的一些数据(提供部分)。 因此,覆盖getItemViewType将不起作用,因为节数据包含在主适配器中,所以它甚至不能到达那里。 所以,最好的,最清洁的过程将是使用抽象 。 忘记多个视图。 使用一个,并进入它,绑定一个自定义的视图。 自定义视图将提供特定的布局文件,并将设置其中包含的控件。 持有者将做它想要做的事情:通过重复使用视图来保存内存。 这样做的好处就是可以有一个干净的层次结构,这个层次结构可以随着时间的推移而变得复杂起来,而不是一个变得太难以维护的大的胖适配器。这里是:

由于这是很多代码放在这里,我把你的示例项目和修改,以提供我所了解你正在尝试做的。 这里是:

https://github.com/fcopardo/exampleCustomViewsInHolder/tree/master

亮点:

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private ArrayList<SingleItemModel> itemsList; private Context context; private String section; public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList, String sectionName) { this.itemsList = itemsList; this.context = context; this.section = sectionName; } @Override public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) { return new SingleItemRowHolder(RowFactory.getRow(context, section)); } @Override public void onBindViewHolder(SingleItemRowHolder holder, int i) { holder.setData(itemsList.get(i)); } @Override public int getItemCount() { return (null != itemsList ? itemsList.size() : 0); } public class SingleItemRowHolder extends RecyclerView.ViewHolder { protected AbstractRowElement rowElement; public SingleItemRowHolder(AbstractRowElement view) { super(view); this.rowElement = view; } public void setData(SingleItemModel singleItemModel){ rowElement.setItem(singleItemModel); } } } 

这是variables布局适配器。 正如你所看到的,它只使用一个ViewHolder和一个工厂来提供你需要的视图实例。

 public class RowFactory { public static AbstractRowElement getRow(Context context, String name){ switch (name){ case "Section 1": return new FullRowElement(context); case "Section 2": return new TextRowElement(context); case "Section 3": return new ImageRowElement(context); default: Log.e("inflate", name); return new FullRowElement(context); } } } 

这提供了自定义视图,每个视图使用不同的布局,但基于区域标题使用相同的数据集。

 public abstract class AbstractRowElement extends CardView{ protected int layout = 0; protected SingleItemModel singleItemModel; public AbstractRowElement(Context context) { super(context); inflateBaseLayout(); } public AbstractRowElement(Context context, AttributeSet attrs) { super(context, attrs); inflateBaseLayout(); } public AbstractRowElement(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); inflateBaseLayout(); } protected void inflateBaseLayout() { this.setContainer(); if(this.layout != 0) { LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(layout, this, true); this.inflateComponents(); } } protected abstract void setContainer(); protected abstract void inflateComponents(); public void setItem(SingleItemModel itemModel){ this.singleItemModel = itemModel; this.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getContext(), singleItemModel.getName()+"\n"+singleItemModel.getDescription(), Toast.LENGTH_SHORT).show(); } }); setData(singleItemModel); } public abstract void setData(SingleItemModel itemModel); } 

最后,这是适配器的基本视图类。 子类定义要使用的布局文件,并将所需的数据放入控件中。 其余的很简单。

这是完全可能的,没有自定义的意见。 你可以这样做:

 int layoutFile = getLayoutForSection(section); View v = LayoutInflater.from(viewGroup.getContext()).inflate(layoutFile, null); 

但是既然我不知道你打算创造多less复杂的观点,最好把事情分开。 玩的开心!