Rishabh
Rishabh

Reputation: 57

ListView adapter onClickListener for list item update

I know this is already been asked a lot of times. but after trying many solutions I can't implement it successfully.

I am making a list with custom layout in it which contains several Views. One of the views is ImageView and I want it to change its icon whenever the user clicks on it.

ListAdapter class I used is as follows:

public class PetitionListAdapter extends BaseAdapter {

    ViewHolder holder = null;

    private LayoutInflater inflater;
    private ArrayList<CustomObject> objects;

    private class ViewHolder {
        ImageView ivsign;
    }

    public PetitionListAdapter(Context context, ArrayList<CustomObject> objects) {
        inflater = LayoutInflater.from(context);
        this.objects = objects;
    }

    public int getCount() {
        return objects.size();
    }

    public CustomObject getItem(int position) {
        return objects.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(final int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.petition_list_layout_beta, null);
            holder.ivsign = convertView.findViewById(R.id.ivsign);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.ivsign.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ImageView img = v.findViewById(R.id.ivsign);
                img.setImageResource(R.drawable.icon_after_click);
            }
        });
        return convertView;
    }
}

Doing this, clickListener works, but instead of that particular imageview, it changes icon of many imageviews at random rows. I know its because of viewHolder. But how can I do this correctly?

Also I had used :-

imgViewArray[position] = holder.textView1;

inside "onListItemClickListener". Doing this it changes the icon at that position as I want, but after scrolling and getting back to that row again, it got changed to default icon again. I know this is because that row get recycled.

Upvotes: 1

Views: 305

Answers (3)

Kingfisher Phuoc
Kingfisher Phuoc

Reputation: 8190

Yes, of course you got this problem. Why? because when list view was scrolled, all your convert views were reused and each convertView was used to display another CustomObject. That means if you changed your first-row image, after scrolling, the row which reused the first-row convertView showed the image as clicked row. So, how to solve it? You have to save the position of item in your CustomObject, something like:

 public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        holder = new ViewHolder();
        convertView = inflater.inflate(R.layout.petition_list_layout_beta, null);
        holder.ivsign = convertView.findViewById(R.id.ivsign);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }
    final CustomObject object = listCustomObject.get(position);
    holder.ivsign.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ((ImageView)v).setImageResource(R.drawable.icon_after_click);
            object.saveResourceId(R.drawable.icon_after_click); // save your resource to use after scrolling.
        }
    });
    // display resouce base on what's saved or display default image.
    holder.ivSign.setImageResource(object.getSavedResourceId()); 
    return convertView;
}

Upvotes: 1

That's not good practice. In OnItemClick you should change the list of objects that is used by the list, then call notifyDataSetChanged(). In getView(...) you should simply make the listView reflect the values from the list. This way, when the list is refreshed, the states of the views remain the same.

Upvotes: 0

Michael
Michael

Reputation: 3239

I think your problem comes from your onClickListener. You are setting it for the ImageView in your ViewHolder, and then inside the onClick method you do v.findViewById.

What you should do is

ImageView img = (ImageView) convertView.findViewById(R.id.ivsign);

And then

img.setOnClickListener(.......);

This works for me, so let me know if you are having any problems implementing.

Upvotes: 0

Related Questions