I have a listview which has two image buttons in the row. Tapping image button change the background color. When I tap on the first list item, image button background change and the view is saved but scrolling bottom of the listview, background color of image button of another list item changes as well. Below is the getView of Custom Adapter. How can I avoid this problem?
public View getView(final int i, View view, ViewGroup viewGroup) {
ViewHolder holder = new ViewHolder();
holder = null;
//view=null;
if (inflater == null) {
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
if (view == null) {
view = inflater.inflate(R.layout.student_list, null);
holder = new ViewHolder();
holder.presentButton = (ImageButton) view.findViewById(R.id.imageView);
holder.absentButton = (ImageButton) view.findViewById(R.id.imageView2);
holder.presentButton.setBackgroundColor(0);
holder.absentButton.setBackgroundColor(0);
view.setTag(holder);
}
else {
holder = (ViewHolder) view.getTag();
}
final SQLiteStudents db1 = new SQLiteStudents(activity.getApplicationContext());
final TextView tvName = (TextView) view.findViewById(R.id.tv_name);
final TextView tvRoll = (TextView) view.findViewById(R.id.tv_roll);
final studentInfo s = students.get(i);
tvRoll.setText(s.getRoll() + ".");
tvName.setText(s.getName());
final Integer roll = Integer.parseInt(s.getRoll());
//ivpresent.setBackgroundColor(0);
final ViewHolder finalHolder1 = holder;
//final ViewHolder finalHolder = holder;
holder.presentButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
db1.updateUser(roll,"present");
finalHolder1.presentButton.setBackgroundColor(GREEN);
finalHolder1.absentButton.setBackgroundColor(0);
//v1.setTag(v.getTag());
//Log.d("present","Roll No: "+String.valueOf(roll));
finalHolder1.presentButton.setTag(Integer.toString(i));
notifyDataSetChanged();
}
});
holder.absentButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
db1.updateUser(roll,"absent");
finalHolder1.presentButton.setBackgroundColor(0);
finalHolder1.absentButton.setBackgroundColor(RED);
//view=null;
//Log.d("absent","Roll No: "+String.valueOf(roll));
finalHolder1.presentButton.setTag(Integer.toString(i));
notifyDataSetChanged();
}
});
return view;
}
public static class ViewHolder {
public ImageButton presentButton;
public ImageButton absentButton;
}
public class CustomListAdapter extends BaseAdapter {
private Activity activity;
private LayoutInflater inflater;
private List<studentInfo> students;
private boolean presentButton = false;
private boolean absentButton = false;
You need to add an else accordingly in your code, see below:
public View getView(final int i, View view, ViewGroup viewGroup) {
ViewHolder holder = new ViewHolder();
holder = null;
//view=null;
if (inflater == null) {
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
if (view == null) {
view = inflater.inflate(R.layout.student_list, null);
holder = new ViewHolder();
holder.presentButton = (ImageButton) view.findViewById(R.id.imageView);
holder.absentButton = (ImageButton) view.findViewById(R.id.imageView2);
holder.presentButton.setBackgroundColor(0);
holder.absentButton.setBackgroundColor(0);
view.setTag(holder);
}
else {
holder = (ViewHolder) view.getTag();
}
final SQLiteStudents db1 = new SQLiteStudents(activity.getApplicationContext());
final TextView tvName = (TextView) view.findViewById(R.id.tv_name);
final TextView tvRoll = (TextView) view.findViewById(R.id.tv_roll);
final studentInfo s = students.get(i);
tvRoll.setText(s.getRoll() + ".");
tvName.setText(s.getName());
final Integer roll = Integer.parseInt(s.getRoll());
//ivpresent.setBackgroundColor(0);
final ViewHolder finalHolder1 = holder;
//final ViewHolder finalHolder = holder;
holder.presentButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
db1.updateUser(roll,"present");
presentButton = true;
}
});
holder.absentButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
db1.updateUser(roll,"absent");
absentButton = true;
}
});
if(presentButton){
finalHolder1.presentButton.setBackgroundColor(GREEN);
finalHolder1.absentButton.setBackgroundColor(0);
//v1.setTag(v.getTag());
//Log.d("present","Roll No: "+String.valueOf(roll));
finalHolder1.presentButton.setTag(Integer.toString(i));
notifyDataSetChanged();
} else {
//set button to some default button like black
}
if(absentButton){
finalHolder1.presentButton.setBackgroundColor(0);
finalHolder1.absentButton.setBackgroundColor(RED);
//view=null;
//Log.d("absent","Roll No: "+String.valueOf(roll));
finalHolder1.presentButton.setTag(Integer.toString(i));
notifyDataSetChanged();
} else {
//set button to some default button like black
}
return view;
}
Related
I have a listview with so much button.When i was click one button of listview another button also click?how can i stop it.
please solve this problem.
Give me any trick how can i stop another button in listview.
this is my code
private class MenuItemsAdapter extends ArrayAdapter<MenuItem> {
private static final String TAG = "MenuItemsAdapter";
public MenuItemsAdapter(Context context, List<MenuItem> menuItems) {
super(context, 0, menuItems);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final MenuItem menuItem = getItem(position);
View view = convertView;
final ViewHolder viewHolder;
LayoutInflater inflater;
inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.menu_item, parent, false);
viewHolder = new ViewHolder();
// viewHolder.half = (TextView) view.findViewById(R.id.half);
viewHolder.name = (TextView) view.findViewById(R.id.name);
viewHolder.description = (TextView) view.findViewById(R.id.description);
viewHolder.price = (TextView) view.findViewById(R.id.price);
viewHolder.add = (Button) view.findViewById(R.id.add);
viewHolder.selectedView = view.findViewById(R.id.selectedView);
viewHolder.remove = (Button) view.findViewById(R.id.remove);
viewHolder.total = (TextView) view.findViewById(R.id.itemTotal);
viewHolder.quantity = (TextView) view.findViewById(R.id.quantity);
view.setTag(viewHolder);
try
{
viewHolder.name.setText(menuItem.name);
viewHolder.description.setText(menuItem.description);
viewHolder.price.setText(String.valueOf(menuItem.price));
viewHolder.add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mApplication.createNewCartIfPossibleAndAskIfNot(
mActivity, mRestaurant,
new MainApplication.OnCreateCartListener() {
#Override
public void onCreateCart(Cart cart) {
cart.addOne(menuItem);
updateItemFromCart(menuItem, viewHolder);
updateCart();
}
});
}
});
viewHolder.remove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mApplication.isCartCreated()) {
return;
}
mApplication.getCart().removeOne(menuItem);
updateItemFromCart(menuItem, viewHolder);
updateCart();
}
});
}catch(NullPointerException e){e.printStackTrace();}
return view;
}
private void updateItemFromCart(MenuItem menuItem, ViewHolder viewHolder) {
if (!mApplication.isCartCreated()) {
return;
}
int quantity = mApplication.getCart().getNOfItemsOfType(menuItem);
if (quantity > 0) {
viewHolder.selectedView.setVisibility(View.VISIBLE);
} else {
viewHolder.selectedView.setVisibility(View.GONE);
}
viewHolder.quantity.setText(String.valueOf(quantity));
viewHolder.total.setText(String.valueOf(quantity
* menuItem.price));
}
class ViewHolder {
TextView name;
TextView description;
TextView price;
Button add;
View selectedView;
Button remove;
TextView total;
TextView quantity;
TextView half;
}
}
I can think of you are missing recycle adapter implementation with static view holder inside adapter. Again, this is hypothetical answer based on text and my past experience. More detailed investigation requires code study.
You can keep null check for your view
final MenuItem menuItem = getItem(position);
View view = convertView;
final ViewHolder viewHolder;
if (convertView == null) {
LayoutInflater inflater;
inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.menu_item, parent, false);
viewHolder = new ViewHolder();
// viewHolder.half = (TextView) view.findViewById(R.id.half);
viewHolder.name = (TextView) view.findViewById(R.id.name);
viewHolder.description = (TextView) view.findViewById(R.id.description);
viewHolder.price = (TextView) view.findViewById(R.id.price);
viewHolder.add = (Button) view.findViewById(R.id.add);
viewHolder.selectedView = view.findViewById(R.id.selectedView);
viewHolder.remove = (Button) view.findViewById(R.id.remove);
viewHolder.total = (TextView) view.findViewById(R.id.itemTotal);
viewHolder.quantity = (TextView) view.findViewById(R.id.quantity);
view.setTag(viewHolder);
}else{
viewHolder= (ViewHolder)convertView.getTag();
}
I created custom adapter to bind with listview but it's showing duplicate songs in listview. please check out the code and let me know if anything is wrong
public class UnfavoriteSongAdapter extends BaseAdapter
{
private Activity activity;
private ArrayList<Media> data;
private static LayoutInflater inflater = null;
private Context context;
public UnfavoriteSongAdapter(Context context, Activity a, ArrayList<Media> d) {
activity = a;
this.context = context;
data = d;
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
GenreFavoriteClickListner genreFavoriteClickListner;
public interface GenreFavoriteClickListner {
public void onFavoriteClickListner(int position,Media media);
}
public void setGenreFavoriteClickListner(GenreFavoriteClickListner genreFavoriteClickListner) {
this.genreFavoriteClickListner = genreFavoriteClickListner;
}
public static class ViewHolder {
public TextView textView_title, textView_artist, textView_time;
public CircleImageView circleImageView_albumphoto, circleImageView_favorite;
public ImageView imageView_play;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View vi = convertView;
final ViewHolder viewHolder;
try {
if (convertView == null) {
viewHolder = new ViewHolder();
final LayoutInflater inflater1 = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflater1.inflate(R.layout.song_listitem_layout, null);
viewHolder.textView_title = (TextView) vi.findViewById(R.id.textView_song_songname);
viewHolder.textView_artist = (TextView) vi.findViewById(R.id.textView_song_artistname);
viewHolder.textView_time = (TextView) vi.findViewById(R.id.textView_song_time);
viewHolder.circleImageView_albumphoto = (CircleImageView) vi.findViewById(R.id.circleImageView_nowplaying_playing);
viewHolder.circleImageView_favorite = (CircleImageView) vi.findViewById(R.id.circleImageView_song_favorite);
viewHolder.imageView_play = (ImageView) vi.findViewById(R.id.imageView_song_playpause);
} else {
viewHolder = (ViewHolder) vi.getTag();
}
if (data.size() <= 0) {
//viewHolder.textview_albumtitle.setText("No Appointment");
} else {
final Media p = data.get(position);
viewHolder.textView_title.setText(p.getSongName());
viewHolder.textView_artist.setText(p.getArtistName());
long millis = Long.parseLong(p.getDuration());
String hms = ReusableModules.getCalculatedTime(millis);
viewHolder.textView_time.setText(hms);
String isplaying = p.getIsPlaying();
int playingid = R.mipmap.play;
if (isplaying != null) {
if(isplaying.contentEquals(Constants.ONE)){
playingid = R.mipmap.runing_music_play;
}
}
viewHolder.imageView_play.setImageResource(playingid);
ReusableModules.setFavoriteToggleButton(p.getIsFavorite(), viewHolder.circleImageView_favorite);
viewHolder.circleImageView_favorite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (genreFavoriteClickListner != null) {
genreFavoriteClickListner.onFavoriteClickListner(position,p);
}
}
});
final String finalUrl = p.getAlbumUrl();
viewHolder.circleImageView_albumphoto.post(new Runnable() {
#Override
public void run() {
BaseActivity.imageLoader.displayImage(finalUrl,
viewHolder.circleImageView_albumphoto, SplashScreenActivity.displayImageOptions, new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(Bitmap loadedImage) {
}
});
}
});
vi.setTag(p);
}
} catch (Exception e) {
}
return vi;
}
}
Change in getView() method like this.
viewHolder = new ViewHolder();
if (convertView == null) {
final LayoutInflater inflater1 = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
vi = inflater1.inflate(R.layout.song_listitem_layout, null);
viewHolder.textView_title = (TextView) vi.findViewById(R.id.textView_song_songname);
viewHolder.textView_artist = (TextView) vi.findViewById(R.id.textView_song_artistname);
viewHolder.textView_time = (TextView) vi.findViewById(R.id.textView_song_time);
viewHolder.circleImageView_albumphoto = (CircleImageView) vi.findViewById(R.id.circleImageView_nowplaying_playing);
viewHolder.circleImageView_favorite = (CircleImageView) vi.findViewById(R.id.circleImageView_song_favorite);
viewHolder.imageView_play = (ImageView) vi.findViewById(R.id.imageView_song_playpause);
and remove this
else {
viewHolder = (ViewHolder) vi.getTag();
}
in last of getView() method
convertView.setTag(holder);
try this and tell me it works or not?
move
vi.setTag(viewholder);
inside
if(convert==null){
viewHolder = new ViewHolder();
final LayoutInflater inflater1 = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflater1.inflate(R.layout.song_listitem_layout, null);
viewHolder.textView_title = (TextView) vi.findViewById(R.id.textView_song_songname);
viewHolder.textView_artist = (TextView) vi.findViewById(R.id.textView_song_artistname);
viewHolder.textView_time = (TextView) vi.findViewById(R.id.textView_song_time);
viewHolder.circleImageView_albumphoto = (CircleImageView) vi.findViewById(R.id.circleImageView_nowplaying_playing);
viewHolder.circleImageView_favorite = (CircleImageView) vi.findViewById(R.id.circleImageView_song_favorite);
viewHolder.imageView_play = (ImageView) vi.findViewById(R.id.imageView_song_playpause);
// here
vi.setTag(viewholder);
}
and remove this:
final String finalUrl = p.getAlbumUrl();
viewHolder.circleImageView_albumphoto.post(new Runnable() {
#Override
public void run() {
BaseActivity.imageLoader.displayImage(finalUrl,
viewHolder.circleImageView_albumphoto, SplashScreenActivity.displayImageOptions, new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(Bitmap loadedImage) {
}
});
}
});
remove this **vi.setTag(p);**
Add vi.setTag(p) inside :
if(convertView == null){
vi.setTag(p);
}
set tag for view holder if view holder null. Add last line of code
if (convertView == null) {
viewHolder = new ViewHolder();
final LayoutInflater inflater1 = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflater1.inflate(R.layout.song_listitem_layout, null);
viewHolder.textView_title = (TextView) vi.findViewById(R.id.textView_song_songname);
viewHolder.textView_artist = (TextView) vi.findViewById(R.id.textView_song_artistname);
viewHolder.textView_time = (TextView) vi.findViewById(R.id.textView_song_time);
viewHolder.circleImageView_albumphoto = (CircleImageView) vi.findViewById(R.id.circleImageView_nowplaying_playing);
viewHolder.circleImageView_favorite = (CircleImageView) vi.findViewById(R.id.circleImageView_song_favorite);
viewHolder.imageView_play = (ImageView) vi.findViewById(R.id.imageView_song_playpause);
/************ Set holder with LayoutInflater ************/
vi.setTag( viewHolder );
}
//check you data size getCount,its a good practice. not in getview method.
#Override
public int getCount() {
if(data!=null && data.size()> 0)
return data.size();
else
return 0;
}
I suggest you to replace getview method and check you data once because your adapter code seems perfect.
Description:
I'm currently implementing a custom ListViewAdapter using the ViewHolder design pattern. The adapter is using a layout with a button that toggles the visibility of a RelativeLayout.
Problem:
When I click the button and the RelativeLayout is shown, everything seems to work fine until I scroll down. When I scroll down, I see that other listitems have been effected by the previous button click, so the RelativeLayout is visible on other (wrong) items. The item that is effected by the button click seems to be the one that is recycled when I scroll down. Please note that everything else works correct, texts etc. are set at the correct position.
Code:
CustomListAdapter
public class ItemsListAdapter extends ArrayAdapter<Item> {
private Context mContext;
private List<Item> mItems;
public ItemsListAdapter(Context context, int resource, List<Item> objects) {
super(context, resource);
mContext = context;
mItems = objects;
}
static class ViewHolder {
View mView;
boolean mExpanded;
public ViewHolder(View view, boolean expanded)
{
mView = view;
mExpanded = expanded;
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
final Item item = getItem(position);
final ViewHolder holder;
if (v == null) {
LayoutInflater mInflater = (LayoutInflater)
mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
v = mInflater.inflate(R.layout.custom_list_item, null);
holder = new ViewHolder(v, false);
v.setTag(holder);
} else {
holder = (ViewHolder) v.getTag();
}
if(item != null)
{
TextView tvName = (TextView) holder.mView.findViewById(R.id.tv_name);
tvName.setText(item.getName());
RelativeLayout rlExpand = (RelativeLayout) holder.mView.findViewById(R.id.rl_expand);
if(holder.mExpanded) {
rlExpand.setVisibility(View.VISIBLE);
}
else {
rlExpand.setVisibility(View.GONE);
}
TextView tvDescription = (TextView) holder.mView.findViewById(R.id.tv_description);
if(tvDescription != null)
tvDescription.setText(item.getDescription());
final ImageButton ibExpand = (ImageButton) holder.mView.findViewById(R.id.ib_expand);
ibExpand.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RelativeLayout rlExpand = (RelativeLayout) holder.mView.findViewById(R.id.rl_expand);
if (rlExpand.getVisibility() == View.GONE) {
v.setVisibility(View.INVISIBLE);
rlExpand.setVisibility(View.VISIBLE);
holder.mExpanded = true;
}
}
});
ImageButton ibCollapse = (ImageButton) holder.mView.findViewById(R.id.ib_collapse);
ibCollapse.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RelativeLayout rlExpand = (RelativeLayout) holder.mView.findViewById(R.id.rl_expand);
ibExpand.setVisibility(View.VISIBLE);
rlExpand.setVisibility(View.GONE);
holder.mExpanded = false;
}
});
}
return v;
}
#Override
public int getCount() {
return mItems.size();
}
#Override
public Truism getItem(int position) {
return mItems.get(position);
}
Any help is highly appreciated! Thank you in advance!
Try to change:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
final Item item = getItem(position);
final ViewHolder holder;
if (v == null) {
LayoutInflater mInflater = (LayoutInflater)
mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
v = mInflater.inflate(R.layout.custom_list_item, null);
holder = new ViewHolder(v, false);
v.setTag(holder);
} else {
holder = (ViewHolder) v.getTag();
}
if(item != null)
{
TextView tvName = (TextView) holder.mView.findViewById(R.id.tv_name);
tvName.setText(item.getName());
RelativeLayout rlExpand = (RelativeLayout) holder.mView.findViewById(R.id.rl_expand);
if(item.isExpanded) {
rlExpand.setVisibility(View.VISIBLE);
}
else {
rlExpand.setVisibility(View.GONE);
}
TextView tvDescription = (TextView) holder.mView.findViewById(R.id.tv_description);
if(tvDescription != null)
tvDescription.setText(item.getDescription());
[...]
}
return v;
}
Change holder.mExpanded to item.isExpanded
I am creating an app where there are images in a custom Listview. The database put a picture or another. Clicking the image has to change. But when I click the image is not changed at the correct ImageView. It changes other ImageView.
I need any help. thanks
public View getView(final int position, View convertView, ViewGroup parent) {
View v = convertView;
final MonumentosHolder holder = new MonumentosHolder();
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.listview_row, null);
TextView tv = (TextView) v.findViewById(R.id.textoListviewNombre);
ImageView img3 = (ImageView) v.findViewById(R.id.imagenVisto);
holder.texto = tv;
holder.imagenVisto = img3;
v.setTag(holder);
}
else {
holder = (MonumentosHolder) v.getTag();
}
holder.position = position;
final MonumentosObj p = monumentosLista.get(position);
holder.texto.setText(p.getNombre());
if (p.getVisto().equals("n")) {
holder.imagenVisto.setImageResource(R.drawable.vistorojo);
} else {
holder.imagenVisto.setImageResource(R.drawable.vistoverde);
}
holder.imagenVisto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MonumentosObj p1 = monumentosLista.get(holder.position);
if (p1.getVisto().equals("s")) {
holder.imagenVisto.setImageResource(R.drawable.vistorojo);
p1.setVisto("n");
} else {
holder.imagenVisto.setImageResource(R.drawable.vistoverde);
p1.setVisto("s");
}
MonumentosAdapter.updateMonumentos(p1);
MonumentosObj p = monumentosLista.get(holder.position);
}
});
imageLoader.displayImage(imageUrls[position], holder.imagen, options, animateFirstListener);
return v;
}
EDIT
Onclick not change the correct image. But when I scroll the listview to below and and return to top, the correct image has changed...
I think that bit of code maybe wrong :
holder.imagenVisto.setOnClickListener(new View.OnClickListener() {
private int pos = position;
#Override
public void onClick(View v) {
MonumentosObj p1 = monumentosLista.get(pos);
Try to store position inside holder object and when assigning it in onClick Listener instead
private int pos = position;
do
private int pos = holder.getPosition()
Remember that android ListViews are not loading all items at one time it just loads thats what is visible and few items beyond that,
Also remember that positions of your items in your Arrays doesn't change you may use it somehow :)
try to change
holder.imagenVisto.setOnClickListener(new View.OnClickListener()
by
holder.imagenVisto.setOnClickListener(new OnClickListener()
I think your click listener affect early items in your list!
do this:
put a long item in your viewHolder:
class MonumentosHolder {
.
.
.
long position;
}
and then in your getView, set the holder positon:
View v = convertView;
--EDITED--
final MonumentosHolder holder = new MonumentosHolder();
--END EDITED--
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.listview_row, null);
TextView tv = (TextView) v.findViewById(R.id.textoListviewNombre);
ImageView img3 = (ImageView) v.findViewById(R.id.imagenVisto);
holder.texto = tv;
holder.imagenVisto = img3;
v.setTag(holder);
}
else {
holder = (MonumentosHolder) v.getTag();
}
**holder.postion = position;**
and then click listener would be like this:
EDITED
holder.imagenVisto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MonumentosObj p1 = monumentosLista.get(**holder.position**);
if (p1.getVisto().equals("s")) {
holder.imagenVisto.setImageResource(R.drawable.vistorojo);
p1.setVisto("n");
} else {
holder.imagenVisto.setImageResource(R.drawable.vistoverde);
p1.setVisto("s");
}
MonumentosAdapter.updateMonumentos(p1);
MonumentosObj p = monumentosLista.get(holder.position);
}
});
EDIT 4
remove the final modifier from holder, define another MonumentosHolder named finalHolder like this:
public View getView(final int position, View convertView, ViewGroup parent) {
View v = convertView;
MonumentosHolder holder = new MonumentosHolder();
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.listview_row, null);
TextView tv = (TextView) v.findViewById(R.id.textoListviewNombre);
ImageView img3 = (ImageView) v.findViewById(R.id.imagenVisto);
holder.texto = tv;
holder.imagenVisto = img3;
v.setTag(holder);
}
else {
holder = (MonumentosHolder) v.getTag();
}
holder.position = position;
final MonumentosObj p = monumentosLista.get(position);
holder.texto.setText(p.getNombre());
if (p.getVisto().equals("n")) {
holder.imagenVisto.setImageResource(R.drawable.vistorojo);
} else {
holder.imagenVisto.setImageResource(R.drawable.vistoverde);
}
final MonumentosHolder finalHolder = holder;
holder.imagenVisto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MonumentosObj p1 = monumentosLista.get(finalHolder.position);
if (p1.getVisto().equals("s")) {
holder.imagenVisto.setImageResource(R.drawable.vistorojo);
p1.setVisto("n");
} else {
holder.imagenVisto.setImageResource(R.drawable.vistoverde);
p1.setVisto("s");
}
MonumentosAdapter.updateMonumentos(p1);
MonumentosObj p = monumentosLista.get(finalHolder.position);
}
});
imageLoader.displayImage(imageUrls[position], holder.imagen, options, animateFirstListener);
return v;
}
I have found a mysterious problem that may be a bug!
I have a list in my fragment. Each row has a button. List shouldn't respond to click however buttons are clickable.
In order to get which button has clicked I have created a listener and implement it in my fragment. This is the code of my adapter.
public class AddFriendsAdapter extends BaseAdapter {
public interface OnAddFriendsListener {
public void OnAddUserClicked(MutualFriends user);
}
private final String TAG = "*** AddFriendsAdapter ***";
private Context context;
private OnAddFriendsListener listener;
private LayoutInflater myInflater;
private ImageDownloader imageDownloader;
private List<MutualFriends> userList;
public AddFriendsAdapter(Context context) {
this.context = context;
myInflater = LayoutInflater.from(context);
imageDownloader = ImageDownloader.getInstance(context);
}
public void setData(List<MutualFriends> userList) {
this.userList = userList;
Log.i(TAG, "List passed to the adapter.");
}
#Override
public int getCount() {
try {
return userList.size();
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = myInflater.inflate(R.layout.list_add_friends_row, null);
holder = new ViewHolder();
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/ITCAvantGardeStd-Demi.ttf");
holder.tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);
holder.tvUserName.setTypeface(font);
holder.ivPicture = (ImageView) convertView.findViewById(R.id.ivPicture);
holder.btnAdd = (Button) convertView.findViewById(R.id.btnAdd);
holder.btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e(TAG, "Item: " + position);
listener.OnAddUserClicked(userList.get(position));
}
});
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvUserName.setText(userList.get(position).getName());
imageDownloader.displayImage(holder.ivPicture, userList.get(position).getPhotoUrl());
return convertView;
}
public void setOnAddClickedListener(OnAddFriendsListener listener) {
this.listener = listener;
}
static class ViewHolder {
TextView tvUserName;
ImageView ivPicture;
Button btnAdd;
}
}
When I run the app, I can see my rows however since my list is long and has over 200 items when i goto middle of list and click an item then returned position is wrong (it's something like 7, sometimes 4 and etc.).
Now what is the mystery?
If I active on item listener of list from my fragment and click on row then correct row position will be displayed while on that row if I click on button then wrong position will be displayed.
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.e(TAG, "item " + position + " clicked.");
}
});
Result in logcat:
05-09 10:22:25.228: E/AddFriendsFragment(20296): item 109 clicked.
05-09 10:22:34.453: E/*** AddFriendsAdapter ***(20296): Item: 0
Any suggestion would be appreciated. Thanks
Because the convertView and holder will be recycled to use, move your setOnClickListener out of the if else statement:
if (convertView == null) {
convertView = myInflater.inflate(R.layout.list_add_friends_row, null);
holder = new ViewHolder();
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/ITCAvantGardeStd-Demi.ttf");
holder.tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);
holder.tvUserName.setTypeface(font);
holder.ivPicture = (ImageView) convertView.findViewById(R.id.ivPicture);
holder.btnAdd = (Button) convertView.findViewById(R.id.btnAdd);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
Log.e(TAG, "Item: " + position);
listener.OnAddUserClicked(userList.get(position));
}
});
It is not the best solution for that,because there will be some performance issue. I suggest you create a Map for your view and create a new view for your item then just use the relative view for each view.
I think it will be a better solution with best performance:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = myInflater.inflate(R.layout.list_add_friends_row, null);
holder = new ViewHolder();
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/ITCAvantGardeStd-Demi.ttf");
holder.tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);
holder.tvUserName.setTypeface(font);
holder.ivPicture = (ImageView) convertView.findViewById(R.id.ivPicture);
holder.btnAdd = (Button) convertView.findViewById(R.id.btnAdd);
holder.btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer pos = (Integer)v.getTag();
Log.e(TAG, "Item: " + pos);
listener.OnAddUserClicked(userList.get(pos));
}
});
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvUserName.setText(userList.get(position).getName());
imageDownloader.displayImage(holder.ivPicture, userList.get(position).getPhotoUrl());
holder.btnAdd.setTag(position);
return convertView;
}
You can also manage your view by yourself. Create every unique view for your item, don't recycle view.
//member various
private Map<Integer, View> myViews = new HashMap<Integer, View>();
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View view = myViews.get(position);
if (view == null) {
view = myInflater.inflate(R.layout.list_add_friends_row, null);
//don't need use the holder anymore.
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/ITCAvantGardeStd-Demi.ttf");
holder.tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);
holder.tvUserName.setTypeface(font);
holder.ivPicture = (ImageView) convertView.findViewById(R.id.ivPicture);
holder.btnAdd = (Button) convertView.findViewById(R.id.btnAdd);
holder.btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer pos = (Integer)v.getTag();
Log.e(TAG, "Item: " + pos);
listener.OnAddUserClicked(userList.get(pos));
}
});
holder.tvUserName.setText(userList.get(position).getName());
imageDownloader.displayImage(holder.ivPicture,
userList.get(position).getPhotoUrl());
myViews.put(position, view);
}
return view;
}
Did you tried doing something like this:
holder.btnAdd.setTag(Integer.valueOf(position));
And then retrieve wich row was clicked in the callback for the button, like this:
public void btnAddClickListener(View view)
{
position = (Integer)view.getTag();
Foo foo = (Foo)foos_adapter.getItem(position); //get data of row(position)
//do some
}
Another approach I found useful (if you are using the ViewHolder pattern of course) is to set the index on a separate attribute whenever getView() is called, then inside your onClickListener you just have to reference your holder's position attribute, something like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if(convertView == null){
convertView = View.inflate(mContext, R.layout.contact_picker_row,null);
holder = new ViewHolder();
holder.body = (RelativeLayout)convertView.findViewById(R.id.numberBody);
convertView.setTag(holder);
}else{
holder = (ViewHolder)convertView.getTag();
}
holder.position = position;
holder.body.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext,"Clicked on: "+holder.position,Toast.LENGTH_LONG).show();
}
});
return convertView;
}
private class ViewHolder{
RelativeLayout body;
int position;
}