Reputation: 891
I have a list of strings in a RecyclerView. I need to be able to click on an item in the list and change the background yellow. I am able to click on an item and change the background, but when I scroll down the list, I see another item in the list has also had its background turned to yellow?
I have tried many different ways of implementing this. I tried setting up an Interface, having the click in the ViewHolder etc.
My code is below.
Activity:
[Activity(Label = "PregnancyListActivity")]
public class PregnancyListActivity : Activity
{
RecyclerView mRecyclerView;
RecyclerView.LayoutManager mLayoutManager;
PregnantAnimalAdapter mAdapter;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.PregnancyListLayout);
mRecyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView);
// Plug in the linear layout manager:
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.SetLayoutManager(mLayoutManager);
// Plug in my adapter:
mAdapter = new PregnantAnimalAdapter();
mAdapter.ItemClick += MAdapter_ItemClick;
mRecyclerView.SetAdapter(mAdapter);
}
}
View Holder
[Activity(Label = "PregnantAnimalViewHolder")]
public class PregnantAnimalViewHolder : RecyclerView.ViewHolder
{
public LinearLayout mBackground { get; private set; }
public TextView mAnimalTag { get; private set; }
public PregnantAnimalViewHolder(View itemView) : base(itemView)
{
// Locate and cache view references:
mBackground = itemView.FindViewById<LinearLayout>(Resource.Id.pregnancyBackground);
mAnimalTag = itemView.FindViewById<TextView>(Resource.Id.animalTag);
}
}
Adapter:
public class PregnantAnimalAdapter : RecyclerView.Adapter
{
public PregnantAnimalAdapter pregnantAnimalAdapter;
public List<PregAnimals> mAnimals;
public PregnantAnimalAdapter()
{
mAnimals = new List<PregAnimals>{
new PregAnimals("111", false),
new PregAnimals("112", false),
new PregAnimals("113", false),
new PregAnimals("114", false),
new PregAnimals("115", false),
new PregAnimals("221", false),
new PregAnimals("222", false),
new PregAnimals("223", false),
new PregAnimals("224", false),
new PregAnimals("225", false),
new PregAnimals("331", false),
new PregAnimals("332", false),
new PregAnimals("333", false),
new PregAnimals("444", false),
new PregAnimals("443", false),
new PregAnimals("554", false),
new PregAnimals("4435", false),
new PregAnimals("4234", false),
new PregAnimals("543", false),
new PregAnimals("3452", false),
new PregAnimals("3321", false),
new PregAnimals("6676", false),
new PregAnimals("4367", false)
};
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From(parent.Context).
Inflate(global::RecordMilk.Resource.Layout.PregnancyItem, parent, false);
PregnantAnimalViewHolder vh = new PregnantAnimalViewHolder(itemView);
vh.mBackground.Click += (object sender, EventArgs e) => {
mAnimals[vh.LayoutPosition].Preg = true;
};
return vh;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
PregnantAnimalViewHolder vh = holder as PregnantAnimalViewHolder;
vh.mAnimalTag.Text = mAnimals[position].Tag;
if (mAnimals[position].Preg == true)
{
vh.mBackground.SetBackgroundResource(RecordMilk.Resource.Color.munster_yellow);
}
}
public override int ItemCount
{
get { return mAnimals.Count; }
}
}
public class PregAnimals
{
public string Tag { get; set; }
public bool Preg { get; set; }
public PregAnimals(string tag, bool preg)
{
Tag = tag;
Preg = preg;
}
}
I am beyond confused as to why it won't just set the item in the list. Any help would be hugely appreciated.
Thanks in advance!
Upvotes: 4
Views: 4261
Reputation: 101
Try to add this line in the adapter:
@Override
public int getItemViewType(int position) {
return position;
}
Upvotes: 9
Reputation: 8090
The problem is the RecyclerView is doing what it should - recycling views. The View whose color you changed, is being reused for a new item, but its color is still selected.
Assuming you want the selection to stay, you need to keep track of which one is selected, and in the OnBindViewHolder set the background color to the selected or unselected color. Otherwise just set the background to unselected.
Also, you can just create a StateListDrawable and assign that to the background that has a state for selected/unselected, so all you need to do is set the View's state to selected. The advantage is it keeps all of your styling in resources.
public class PregnantAnimalViewHolder : RecyclerView.ViewHolder
{
public LinearLayout mBackground { get; private set; }
public TextView mAnimalTag { get; private set; }
public bool Selected {get;set;}
public int position {get;set;}
public PregnantAnimalViewHolder(View itemView) : base(itemView)
{
// Locate and cache view references:
mBackground = itemView.FindViewById<LinearLayout>(Resource.Id.pregnancyBackground);
mAnimalTag = itemView.FindViewById<TextView>(Resource.Id.animalTag);
}
}
Then in the OnBindViewHolder
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
PregnantAnimalViewHolder vh = holder as PregnantAnimalViewHolder;
vh.mAnimalTag.Text = mAnimals[position];
vh.position = position;
vh.View.SetBackgroundResource(
vh.Selected?Resource.Color.munster_yellow:Resource.Color.whatever);
// or vh.View.SetSelected(vh.Selected) for using StateListDrawable as the background
}
Upvotes: 1