Reputation: 4450
In my RecyclerView
item, there is a button along with other views. I am hiding the button when it is clicked. Problem is, if I click the button on 1st item, the button on 8th item is auto clicked, if I click button on 2nd item, button on 9th item is auto clicked & so on. How to solve this problem?
Adapter class :
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
private List<Model> models;
Model model;
// public MyAdapterListener onClickListener;
SparseBooleanArray mStateButtons = new SparseBooleanArray();
public Adapter(List<Model> models){
this.models = models;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_row, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
String question = models.get(position).getQues();
final String optA = models.get(position).getOptA();
final String optB = models.get(position).getOptB();
final String optC = models.get(position).getOptC();
final String optD = models.get(position).getOptD();
final String answer = models.get(position).getAns();
holder.question.setText(question);
holder.optA.setText(optA);
holder.optB.setText(optB);
holder.optC.setText(optC);
holder.optD.setText(optD);
holder.options.setTag(position);
holder.options.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
int radioButtonID = group.getCheckedRadioButtonId();
int clickedPos = (Integer) group.getTag();
models.get(clickedPos).setChecked(radioButtonID);
}
});
holder.options.check(models.get(position).getChecked());
final int currentPosition = holder.getAdapterPosition();
final Button button = holder.seeAnswer;
if(mStateButtons.valueAt(currentPosition)) {
button.setVisibility(View.GONE);
} else {
button.setVisibility(View.VISIBLE);
}
holder.seeAnswer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mStateButtons.put(position, true);
}
});
}
@Override
public int getItemCount() {
return Models.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
TextView question;
RadioButton optA, optB, optC, optD;
Button seeAnswer;
RadioGroup options;
public ViewHolder(View itemView) {
super(itemView);
options = (RadioGroup) itemView.findViewById(R.id.rgMcqOptions);
question = (TextView) itemView.findViewById(R.id.tvMcqQues);
optA = (RadioButton) itemView.findViewById(R.id.rbOptA);
optB = (RadioButton) itemView.findViewById(R.id.rbOptB);
optC = (RadioButton) itemView.findViewById(R.id.rbOptC);
optD = (RadioButton) itemView.findViewById(R.id.rbOptD);
seeAnswer = (Button) itemView.findViewById(R.id.btnSeeAnswer);
}
}
}
Upvotes: 2
Views: 1542
Reputation: 1315
The problem seems to be that you are not initializing correctly the state of the Button
. Cells in a RecyclerView
are reused when they appear or hide in the screen. That means that if you hide the 1st position and then this view is recycled to create the 8th, the Button
keeps its state, in this case INVISIBLE
Try to assign a value all cases or init the value to VISIBLE
.
Upvotes: 1
Reputation: 18748
You need some way to keep track of which buttons should be hidden and which should not. This is the responsibility of your adapter, so you need to add some form of array to keep track of button states there. A SparseBooleanArray
is an efficient and appropriate option:
private SparseBooleanArray hideButtons = new SparseBooleanArray();
In onBindView
you need to update the view for the current item being bound, including updating the button visibility:
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
holder.seeAnswer.setVisibility( hideButtons.get(position, false) ? View.GONE : View.VISIBLE );
...
}
And of course you need to actually set the visibility - and store it in the SparseBooleanArray
when clicking the button. Putting this event handler in the ViewHolder
is a good option:
class ViewHolder extends RecyclerView.ViewHolder{
Button seeAnswer;
...
ViewHolder(View itemView) {
super(itemView);
seeAnswer = (Button) itemView.findViewById(R.id.btnSeeAnswer);
seeAnswer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
seeAnswer.setVisibility(View.GONE);
hideButtons.put(getAdapterPosition(), true);
}
});
...
}
}
This is a tested and verified solution, so if you follow this and it still doesn't work, the cause of your problem is somewhere else.
Upvotes: 1
Reputation: 29783
This usually happens because you forgot to keep the state of the Button in case it's being recycled. You can use SparseBooleanArray
to store the states. Something like this:
public class YourAdapter ... {
// variable to save the state of buttons.
// we use state true as hidden, false as visible
SparseBooleanArray mStateButtons = new SparseBooleanArray();
...
@Override
public void onBindViewHolder(ContactsAdapter.ViewHolder viewHolder, int position) {
final int currentPosition = viewHolder.getAdapterPosition();
// assume this is your button
Button button = viewHolder.yourButton;
// set the previous state to button
if(mStateButtons.valueAt(currentPosition)) {
// state is true, so the button need to be hide.
button.setVisibility(View.GONE);
} else {
// default value is valse, which is we set as visible.
button.setVisibility(View.VISIBLE);
}
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// save the state when clicked
mStateButtons.put(currentPosition, true);
}
});
}
}
UPDATE
Try moving the click handling on ViewHolder, something like this:
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
...
Button seeAnswer;
public ViewHolder(View itemView) {
super(itemView);
...
seeAnswer = (Button) itemView.findViewById(R.id.btnSeeAnswer);
itemView.setOnClickListener(this);
}
// Handles the row being being clicked
@Override
public void onClick(View view) {
mStateButtons.put(getAdapterPosition(), true);
view.setVisibility(View.GONE);
}
}
then remove the button.setOnClickListener(new View.OnClickListener()
in onBindViewHolder
.
Upvotes: 1