问题
Inside my Listview's ListItem i have a multiple controls and one among them is imageview. My purpose is that user when clicks on that image, source should change to something else. I am implementing ViewHolder Pattern, and right now i am able to toggle the source on click. My current problem is that when i scroll down new views are getting created(re-used), and when i try to move Up again the listitem where i toggled the image are again getting created with default image source as my datasource LIST has remained same. Kindly help.
private class ViewHolder : Java.Lang.Object
{
//Activity context;
public MyTextView HadithBook;
public MyTextView HadithChapter;
public MyTextView HadithText;
public ImageView FavButton;
public ImageView ShareButton;
public EventHandler Handler;
public MyTextView RowId;
public MyTextView IsFavorite;
}
public override View GetView (int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
if (convertView == null)
{
convertView = context.LayoutInflater.Inflate (Resource.Layout.HadithListViewItem, null);
holder = new ViewHolder ();
holder.HadithBook = convertView.FindViewById<MyTextView> (Resource.Id.HadithBook);
holder.HadithChapter = convertView.FindViewById<MyTextView> (Resource.Id.HadithChapter);
holder.HadithText = convertView.FindViewById<MyTextView> (Resource.Id.HadithText);
holder.FavButton = convertView.FindViewById<ImageView> (Resource.Id.favButton);
holder.ShareButton = convertView.FindViewById<ImageView> (Resource.Id.ShareButton);
holder.IsFavorite = convertView.FindViewById<MyTextView> (Resource.Id.IsFavorite);
holder.RowId = convertView.FindViewById<MyTextView> (Resource.Id.RowId);
holder.Handler = (s, e) => FavoriteHandler (s, e, holder);
convertView.Tag = holder;
}
if (holder == null)
{
holder = (ViewHolder)convertView.Tag;
holder.FavButton.Click -= holder.Handler;
}
var item = items[position];
holder.HadithBook.Text = item.BookName;
holder.HadithChapter.Text = item.ChapterName + " - " + item.HadithID;
if (!string.IsNullOrEmpty (keyword) & !string.IsNullOrWhiteSpace (keyword)) {
holder.HadithText.TextFormatted = (Html.FromHtml (ReplaceEx ((item.HadithText).ToString (), keyword, "<font color='#ff9000'><b>" + keyword + "</b></font>")));
} else {
holder.HadithText.TextFormatted =Html.FromHtml(item.HadithText);
}
if (holder.FavButton.Tag.Equals(0))
{
holder.FavButton.Tag = 0;
holder.FavButton.SetImageResource (Resource.Drawable.ic_action_not_important);
} else
{
holder.FavButton.Tag = 1;
holder.FavButton.SetImageResource (Resource.Drawable.ic_action_important);
}
holder.FavButton.Click += holder.Handler;
convertView.SetOnClickListener (null);
return convertView;
}
void FavoriteHandler (object sender, EventArgs e, ViewHolder holder)
{
Database db = new Database ();
if (holder.FavButton.Tag.Equals (0)) {
holder.FavButton.SetImageResource (Resource.Drawable.ic_action_important);
holder.FavButton.Tag = 1;
db.InsertQuery ("insert into favorite values ('" + holder.RowId + "');");
} else if (holder.FavButton.Tag.Equals (1)) {
holder.FavButton.SetImageResource (Resource.Drawable.ic_action_not_important);
holder.FavButton.Tag = 0;
db.InsertQuery ("Delete from favorite where id ='" + holder.RowId + "';");
}
db = null;
}
回答1:
This is a trap nearly everyone falls into when learning how to implement adapters.
The problem is that you are storing data in the viewholder that is unique to the position. For instance, you are reading from holder.FavButton.Tag before setting it with values, thus your current code expects that tag to retain data for you.
As you scroll through the listview, the views are recycled, and thus you are reading data from another position. You cannot cache position-dependent-data in the view holder. Instead its used to hold layout elements which are common to all positions (i.e. the view is covertable, hence the name "convertView" in the getView method). You'll have to cache that data by other means, like a hashmap that caches your data by position.
来源:https://stackoverflow.com/questions/22124819/facing-critical-issue-toggle-image-source-inside-listview-using-viewholder-patt