Reputation: 57
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 View
s. 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
Reputation: 8190
Yes, of course you got this problem. Why? because when list view was scrolled, all your convert view
s 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
Reputation: 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
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