RecyclerView Several types of layout in adapter class

Is this what I have achieved? 3 different sections, 10 different elements in each section.

Here is a tutorial link I follow and below Screenshot :

enter image description here

Trying to show different Views for each section. how

For section 1 (layout_1.xml)

Section 2 (layout_2.xml)

Section 3 (layout_3.xml)

But showing the view layout layout_1.xml in each section ... (Section 1, 2, 3)

Can I find out where I am mistaken in my code that I missed?

 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(); } }); } } } 
+7
android xml layout adapter android-recyclerview
source share
11 answers

Use this internal getItemViewType adapter:

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

to use multiple layouts according to the position in the recyclerview, you must override the getItemViewType (int position) method inside the adapter: -

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

As already mentioned, for the getItemViewType method of the class is the RecyclerView.Adapter , because if you see in the implementation of this method, you will see that it just returns 0 all the time.

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

And here is the adjusted code of your adapter, which should solve your problem.

 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(); } }); } } } 
+1
source share

You can do it in a simpler way. Pass any flag when initializing the adapter.

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

Use this view to link to the layout. You just need to specify which layout should be inflated during the installation of the adapter.

+1
source share

You need to override the method

 int getItemViewType (int position) 

It gets the line number, and you need to return the "type" of the line ie 1 2 or 3.

Then the result will be passed onCreateViewHolder.

0
source share

Fyi

RecyclerView can also be used to inflate several types of views.

  • It will be easiest for you to create another owner.
  • Create Different Adapters - Best Solutions

Try

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

Count RecyclerView can also be used to inflate several types of views.

0
source share

If, for example, you want to show this list of views:

type1 type2 3 type Type 1 type2 Type3

then this should do the job:

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

If you want to add / remove rows, you can do this by inserting / deleting viewTypes in the viewTypes array, and then call the RecyclerView notifyItemInserted or notifyItemRemoved methods the list will be updated with a new order and type of views.

0
source share

Just use the frame layout with your fragment and add this fragment to your frame, which will be added as you want. Thus, it is also easy to handle. hope this helps you

0
source share

Yes, you need to override the getItemViewType (int position) method, which helps to inflate various views in recyclerview.

I am posting sample code that might help you.

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

}

0
source share

All you have to do is override the getItemViewType() method inside your adapter.

You can write it as:

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

Now the above logic works if your itemsList ArrayList has the first 10 elements of section 1, the next 10 elements of section 2 and the last 10 elements of section 3.

If it is not, you can have an integer sectionNumber field in your SingleItemModel class that indicates the number of the section in which this model belongs. Now you can change the getItemViewType() method as

 @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; } } 
0
source share

Well, if I understood correctly, you want to make a second adapter, one that provides lists of strings, a variable, so it supports different layouts based not on its position, but on some data from the main adapter (one of which contains sections). Therefore, overriding getItemViewType will not work, because the section data is contained in the main adapter, it does not even get there. So, the best and cleanest course is to use ... abstraction . Forget about a few viewers. Use it and tie to it. Custom views will provide both specific layout files and the installed controls included in them. The owner will do what he is intended to: save the ram by reusing the views. The advantage of this is that you can have a clean hierarchy that can grow over time, rather than with a large, bold adapter that becomes too complex to maintain. Here he is:

Since there is a lot of code for this, I took your sample project and modified it to ensure that I understood what you were trying to do. Here he is:

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

Basic moments:

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

This is a variable layout adapter. As you can see, it uses only one ViewHolder and factory to provide the instances you need.

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

this provides custom views, each using a different layout, but working with the same data set based on the section header.

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

Finally, this is the base view class for the adapter. Subclasses define the layout file to use and put the necessary data into the controls. The rest is pretty simple.

This would be entirely possible without custom views. You could just do something like:

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

But since I don’t know how complicated the presentation you intend to create is, it is best to keep things beautifully separated. Enjoy!

0
source share

All Articles