'Seekbars in RecyclerView become "linked". Changing the value in one, changes another
I've set up a RecyclerView and getting some odd behavior when adding Seekbars to every row or "view". I've also tried this just using ListView as well and get the same effect. So when I change the Seekbar on the first item, it changes the value of the seekbar on the seventh item down the list to the exact same value. It seems like they are getting "linked" somehow. Currently, the layout_height is smaller than the list, so its scrollable and I cant see all the items at once, and this is when I notice the problem. However, when the layout_height is maxed to match_parent, and the whole list fits on the screen, this does not happen. I'm really rough guessing this has something to do with how views get inflated and its getting ID's confused or something like this. My RecyclerView Adapter code is listed below. This is my first time using StackOverflow, apologies if I didn't post this in the right area or made any mistakes with formatting. Let me know if I could of done something better here.
Thanks for any help!!
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
private ArrayList<HashMap<String, String>> mData;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
private LinearLayoutManager linearLayoutManager;
// data is passed into the constructor
MyRecyclerViewAdapter(Context context, ArrayList<HashMap<String, String>> data) {
this.mInflater = LayoutInflater.from(context);
this.mData = data;
}
// inflates the row layout from xml when needed
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_row, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each row
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// System.out.println(mData);
ArrayList<HashMap<String, String>> test = mData;
//entry.get("id").toString()
holder.Foods_Text.setText(mData.get(position).get("Food"));
holder.Prices_Text.setText(mData.get(position).get("Price"));
holder.Weights_Text.setText(mData.get(position).get("Weight"));
holder.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar bar) {
}
public void onStartTrackingTouch(SeekBar bar) {
}
public void onProgressChanged(SeekBar bar, int paramInt, boolean paramBoolean) {
int value = bar.getProgress();
// stList.get(position).setNoOfquestions(value);
System.out.println(value);
//update textview while dragging seekbar
// viewHolder.tvValues.setText("" + paramInt); // here in textView the percent will be shown
}
});
}
// total number of rows
@Override
public int getItemCount() {
return mData.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView Foods_Text;
TextView Prices_Text;
TextView Weights_Text;
SeekBar seekBar;
ViewHolder(View itemView) {
super(itemView);
Foods_Text = itemView.findViewById(R.id.Foods);
Prices_Text = itemView.findViewById(R.id.Prices);
Weights_Text = itemView.findViewById(R.id.Weights);
seekBar = itemView.findViewById(R.id.seekBar_Food);
seekBar.setMax(20);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// convenience method for getting data at click position
String getItem(int id) {
return mData.get(id).toString();
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
Solution 1:[1]
Your onBindViewHolder()
method doesn't have anything to set the value (the progress
) of the SeekBar
. This means that, when the view is recycled, the SeekBar
will just re-use the position from the previous item it was bound to.
Imagine that you can fit five rows on screen at once. All SeekBar
s are initially set to 0
. You drag the first one to 100
.
Now you scroll the list. Eventually, the first row will scroll out of view, and its ViewHolder
will be recycled for some row that comes into view (maybe the seventh or eighth row; some "extra" ViewHolder
s are cached). When this row is recycled, since nothing sets the SeekBar
position, it will still display as 100
.
You will have to update onBindViewHolder()
to make sure that the SeekBar
's progress is set correctly every time.
Solution 2:[2]
Add the override method
@Override
public int getItemViewType(int position) {
return position;
}
in the Adapter class
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Ben P. |
Solution 2 | Maclaine |