Reputation: 10286
I have listview with arrayadapter. I want when clicking a button inside list item a specific view in that item (and not in other items) be visibile or invisible.
Heres the code what I'm doing in adapters getView() method:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = vi.inflate(layoutResourceId, null, false);
holder = new Holder();
holder.setShare((ImageView) convertView.findViewById(R.id.share));
holder.setShareButtons((LinearLayout)convertView.findViewById(R.id.shareButtons));
convertView.setTag(holder);
}
holder = (Holder) convertView.getTag();
holder.getShare().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(holder.getShareButtons().getVisibility()==View.GONE){
holder.getShareButtons().setVisibility(View.VISIBLE);
}
else{
holder.getShareButtons().setVisibility(View.GONE);
}
}
});
return convertView;
}
But all I'm getting is strange behavior. The onClickListener and setVisibilty methods are called correctly but my view sometimes get visible and sometimes not, and this depend on list scroll positon .
What I'm doing wrong and how should I solve this ?
Upvotes: 3
Views: 3806
Reputation: 7892
Here is a snippet of my custom Adapter which will give you an example on how to react to an item click within the adapter itself:
Functionality: Every row represents a object which can be seen or not seen. Whether it is seen or not, the image is different. Clicking on an item toggles the image on/off.
public class Exampledapter extends ArrayAdapter<CustomObject> {
private Context mContext;
private int mLayoutResourceId;
private ArrayList<CustomObject> mData = null;
public ExampleAdapter(Context context, int layoutResourceId, ArrayList<CustomObject> data, DataSource datasource) {
super(context, layoutResourceId, data);
this.mLayoutResourceId = layoutResourceId;
this.mContext = context;
this.mData = data;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View lRow = convertView;
ViewHolder holder = null;
if (lRow == null) {
LayoutInflater lInflater = ((Activity) mContext).getLayoutInflater();
lRow = lInflater.inflate(mLayoutResourceId, parent, false);
holder = new ViewHolder();
holder.txtTitle = (TextView) lRow.findViewById(R.id.text_);
holder.imageSeen = (ImageView) lRow.findViewById(R.id.image_toggle);
lRow.setTag(holder);
} else {
holder = (ViewHolder) lRow.getTag();
}
holder.imageSeen.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onListItemClick(position);
}
});
if (mData.get(position).getSeen() == 1) {
holder.imageSeen.setImageBitmap(mImageSeen);
} else {
holder.imageSeen.setImageBitmap(mImageUnseen);
}
holder.txtTitle.setText(mData.get(position).getTitle());
return lRow;
}
protected void onListItemClick(int position) {
if (mData.get(position).isSeen()) {
mData.get(position).setSeen(0);
} else {
mData.get(position).setSeen(1);
}
notifyDataSetChanged();
}
class ViewHolder {
TextView txtTitle;
ImageView imageSeen;
}
}
Upvotes: 1
Reputation: 93561
WHen a list view is scrolled, the child views are reused and reassigned to new positions. This is for efficiency, as creating new views is expensive. However, it puts the burden on the programmer- on every getView call you must completely reset every value of the view. So if pressing a button in the child changes the visibility of one of its members, you need to remember what the visibility should be for each numeric position, and in getView you must set the appropriate visibility for every element.
Upvotes: 4
Reputation: 10001
The holder is meant to keep references to the inner views for performance reasons. It is not related to the data that gets presented in your list - only to the "cells" in your list. You should determine whether stuff is visible or not based on your data.
Upvotes: 1