Search code examples
androidlistadapter

Android: Custom list adapter with progress bar


I have got a custom list adapter that I am trying to use a layout with a progress bar in it for.

My problem is that, when the view is first inflated, I set the progress bar visibility to false. When the item is clicked, I set the progress bar visibility to true. But, if you scroll down the list, random item's progress bars become visible (due to the recycling of the view?).

Any easy ways to remedy this?

public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder = null;

    if (convertView == null) {
        convertView = inflater.inflate(R.layout.imagegriditem, null);

        holder = new ViewHolder();
        holder.heroName = (TextView) convertView.findViewById(R.id.heroName);
        holder.heroImage = (ImageView)convertView.findViewById(R.id.heroImage);
        holder.progressBar = (ProgressBar) convertView.findViewById(R.id.progressBar);
        holder.progressBar.setIndeterminate(false);
        holder.progressBar.setVisibility(View.INVISIBLE);
        holder.progressBar.setIndeterminate(false);
        holder.progressVisible = View.INVISIBLE;
        convertView.setTag(holder);
    }
    else{
        holder = (ViewHolder) convertView.getTag();
    }

    if(holder != null){
        holder.heroName.setText(heroes[position]);
        holder.heroImage.setImageResource(android.R.drawable.ic_dialog_email);
        holder.progressBar.setProgress(10);
    }

    final int pos = position;

    final ViewHolder hold = holder;

    convertView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            hold.progressBar.setProgress(hold.progressBar.getProgress() + 10);
            hold.progressVisible = View.VISIBLE;
            hold.progressBar.setVisibility(View.VISIBLE);
        }
    });

    return convertView;
}

This is basically proof of concept code.. so it's not exactly pretty. But, just trying to get the idea down so I can use it properly.


Solution

  • You’re right. Since view can be recycled and used as an item in another position you should always set visibility for the progress bar based on position in getView. Use AdapterView.OnItemClickListener instead of View.OnClickListener. Keep track of progress bar visibility by using array.

        public class AdapterItem
        {
            public Boolean IsInProgress;
        }
    
    ...    
        Public class CustomAdapter extends BaseAdapter
        {
    
            ArrayList<AdapterItem> _list = new ArrayList<AdapterItem>()
            ...
    
            public View getView(int position, View convertView, ViewGroup parent)
            {
               ...
    
               if (holder != null && _list.size() > position)
               {
                    AdapterItem item = _list.get(position);
    
                holder.progressVisible = Item.IsInProgress ? View. VISIBLE : View.INVISIBLE
               }
            }
    
            public void onItemClick(int position)
            {
                AdapterItem item = _list.get(position);
                item.IsInProgress = !item.IsInProgress;
            }
        }
    
        ...
    
        listView.setOnItemClickListener(new OnItemClickListener() 
        {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                            int position, long id) {
    
                CustomAdapter adpt = (CustomAdapter)parent.getAdapter();
                adpt.onItemClick(position);
            }
        }