Creating ViewHolders for ListViews with various item layouts

I have a ListView with different layouts for different elements. Some elements are delimiters. Some elements are different because they contain different types of data, etc.

I want to implement ViewHolders to speed up the getView process, but I'm not quite sure how to do this. Different layouts have different pieces of data (which makes naming difficult) and different numbers of views that I want to use.

How should I do it?

The best idea I can come up with is to create a common ViewHolder with X elements, where X is the number of views in the layout of the elements with the most of them. For other views with a small number of views, I just use the subsection of these variables in the ViewHolder. So to speak, I have 2 layouts that I use for two different items. One has 3 TextViews and the other has 1. I would create a ViewHolder with three TextView variables and use only one of them for my other element. My problem is that it can get really ugly and look really hacked; especially when the layout of an element can have many views for different types.

Here is a very simple getView:

@Override public View getView(int position, View convertView, ViewGroup parent) { MyHolder holder; View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.layout_mylistlist_item, parent, false); holder = new MyHolder(); holder.text = (TextView) v.findViewById(R.id.mylist_itemname); v.setTag(holder); } else { holder = (MyHolder)v.getTag(); } MyListItem myItem = m_items.get(position); // set up the list item if (myItem != null) { // set item text if (holder.text != null) { holder.text.setText(myItem.getItemName()); } } // return the created view return v; } 

Suppose I had different types of row layouts, I could have a ViewHolder for each row type. But what type would I call a β€œholder” on top? Or I can declare a holder for each type, and then use it for the type of string in which I am included.

+46
android listview listactivity
Aug 18 '10 at 16:51
source share
2 answers

ListView has an integrated type management system. In your adapter, you have several types of elements, each with its own view and layout. Overriding getItemViewType to return the data type for a given position, ListView is required to pass the correct conversion for this data type. Then, in your getView method, just check the data type and use the switch statement to handle each type differently.

Each type of layout should have its own viewer to determine clarity and ease of maintenance. Name ViewHolders something related to each data type to keep everything straight.

Trying to cross all into one ViewHolder is simply not worth the effort.

Change Example

 @Override public View getView(int position, View convertView, ViewGroup parent) { int viewType = this.getItemViewType(position); switch(viewType) { case TYPE1: Type1Holder holder1; View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater)getContext().getSystemService (Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.layout_mylistlist_item_type_1, parent, false); holder1 = new Type1Holder (); holder1.text = (TextView) v.findViewById(R.id.mylist_itemname); v.setTag(holder1); } else { holder1 = (Type1Holder)v.getTag(); } MyListItem myItem = m_items.get(position); // set up the list item if (myItem != null) { // set item text if (holder1.text != null) { holder1.text.setText(myItem.getItemName()); } } // return the created view return v; case TYPE2: Type2Holder holder2; View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.layout_mylistlist_item_type_2, parent, false); holder2 = new Type2Holder (); holder2.text = (TextView) v.findViewById(R.id.mylist_itemname); holder2.icon = (ImageView) v.findViewById(R.id.mylist_itemicon); v.setTag(holder1); } else { holder2 = (Type2Holder)v.getTag(); } MyListItem myItem = m_items.get(position); // set up the list item if (myItem != null) { // set item text if (holder2.text != null) { holder2.text.setText(myItem.getItemName()); } if(holder2.icon != null) holder2.icon.setDrawable(R.drawable.icon1); } // return the created view return v; default: //Throw exception, unknown data type } } 
+105
Aug 18 '10 at 18:12
source share
β€” -

Another example.

Public class CardArrayAdapter extends ArrayAdapter {

 public CardArrayAdapter(Context context) { super(context, R.layout.adapter_card); } @Override public View getView(int position, View view, ViewGroup parent) { final Card card = getItem(position); ViewHolder holder; //if (view != null) { //holder = (ViewHolder) view.getTag(); //} else { Log.d("card.important?", card.name + " = " + Boolean.toString(card.important)); if(card.important) { view = LayoutInflater.from(getContext()).inflate(R.layout.adapter_card_important, parent, false); }else { view = LayoutInflater.from(getContext()).inflate(R.layout.adapter_card, parent, false); } holder = new ViewHolder(view); view.setTag(holder); //} // IMG Picasso.with(getContext()) .load(card.logo) .placeholder(R.drawable.ic_phonebook) .error(R.drawable.ic_phonebook) .fit() .centerCrop() .transform(new CircleTransform()) .into(holder.logo); holder.name.setText(card.name); if(card.important) { holder.category.setVisibility(View.VISIBLE); if (card.category.equals("airline")) { card.category = "airlines"; } int id = getContext().getResources().getIdentifier(card.category, "string", getContext().getPackageName()); holder.category.setText(getContext().getResources().getString(id)); }else { holder.category.setVisibility(View.GONE); } holder.tagline.setText(card.tagline); holder.favorite.setChecked(card.favorite); holder.favorite.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { card.favorite = ((CheckBox) v).isChecked(); card.save(); } }); return view; } static class ViewHolder { @InjectView(R.id.logo) ImageView logo; @InjectView(R.id.name) TextView name; @InjectView(R.id.category) TextView category; @InjectView(R.id.tagline) TextView tagline; @InjectView(R.id.favorite) CheckBox favorite; public ViewHolder(View view) { ButterKnife.inject(this, view); } } 

}

0
May 21 '15 at 18:20
source share



All Articles