Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reusing views in Android Listview with 2 different layouts

I've learned that to maximize efficiency with Android listviews, you should only have as many inflated 'row' views as are needed to fit on the screen. Once a view has moved off the screen, you should reuse it in your getView method, checking if convertView is null or not.

However, how can you implement this idea when you need 2 different layouts for the list? Lets say its a list of orders and 1 layout is for completed orders and the other layout is for in process orders.

This is an example tutorial of the idea my code is using. In my case, I would have 2 row layouts: R.layout.listview_item_product_complete and R.layout.listview_item_product_inprocess

public View getView(int position, View convertView, ViewGroup parent) {  ViewHolder holder = null;  if (convertView == null) {     holder = new ViewHolder();     if(getItemViewType(position) == COMPLETE_TYPE_INDEX) {         convertView = mInflator.inflate(R.layout.listview_item_product_complete, null);         holder.mNameTextView = (TextView) convertView.findViewById(R.list.text_complete);         holder.mImgImageView = (ImageView) convertView.findViewById(R.list.img_complete);     }     else { // must be INPROCESS_TYPE_INDEX         convertView = mInflator.inflate(R.layout.listview_item_product_inprocess, null);         holder.mNameTextView = (TextView) convertView.findViewById(R.list.text_inprocess);         holder.mImgImageView = (ImageView) convertView.findViewById(R.list.img_inprocess);     }     convertView.setTag(holder); } else {     holder = (ViewHolder) convertView.getTag(); }     thisOrder = (Order) myOrders.getOrderList().get(position);     // If using different views for each type, use an if statement to test for type, like above     holder.mNameTextView.setText(thisOrder.getNameValue());     holder.mImgImageView.setImageResource(thisOrder.getIconValue());     return convertView; }  public static class ViewHolder {     public TextView mNameTextView;     public ImageView mImgImageView; } 
like image 504
jamis0n Avatar asked Nov 08 '12 20:11

jamis0n


1 Answers

You need to let the adapter's view recycler know that there is more than one layout and how to distinguish between the two for each row. Simply override these methods:

@Override public int getItemViewType(int position) {     // Define a way to determine which layout to use, here it's just evens and odds.     return position % 2; }  @Override public int getViewTypeCount() {     return 2; // Count of different layouts } 

Incorporate getItemViewType() inside getView(), like this:

if (convertView == null) {     // You can move this line into your constructor, the inflater service won't change.     mInflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);     if(getItemViewType(position) == 0)         convertView = mInflater.inflate(R.layout.listview_item_product_complete, parent, false);     else         convertView = mInflater.inflate(R.layout.listview_item_product_inprocess, parent, false);     // etc, etc... 

Watch Android's Romain Guy discuss the view recycler at Google Talks.

like image 158
Sam Avatar answered Sep 19 '22 06:09

Sam