问题
I am using recyclerView to build a list of toggle buttons (like a numpad), I would like to achieve:
- when user 'turns on' a button by clicking it, 'turns off' all other buttons
I have tried to add an onClickListener
inside the view holder class, and call notifyDataSetChanged()
such that onBindViewHolder(final ViewHolder holder, int position)
is called and then change the state of the button.
But it doesn't work, the button clicked does not change its state.
ViewHolder
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
ToggleButton button;
String id;
public ViewHolder(View itemView) {
super(itemView);
button = (ToggleButton) itemView.findViewById(R.id.toggle);
button.setOnclickListener(this);
}
@Override
public void onClick(View view) {
((ToggleButton) view).setChecked(true);
int pos = getAdapterPosition();
if (pos != RecyclerView.NO_POSITION) {
selected = pos; //store the position of the user clicked button
notifyDataSetChanged();
}
}
onBindViewHolder() in my adpater class
public void onBindViewHolder(final ViewHolder holder, int position) {
String data = mData.get(position);
holder.id = data;
holder.button.setText(data);
holder.button.setTextOn(data);
holder.button.setTextOff(data);
if (position != selected) { //if the button is not the user chosen one
if (holder.button.isChecked()) { // and it's in 'ON' state
holder.button.toggle(); // toggle it to switch 'OFF'
}
}
回答1:
There are a couple of things you are doing incorrectly. The ViewHolder
should contain only views and not click handlers or strings etc. (The clue is in the name). You add the handlers and manipulate the views when you bind the ViewHolder to your data class.
From what I can determine, you want a simple list of toggle buttons. When one button is on, the others should turn off. The test adapter I created for you below demonstrates that.
Ideally, you would avoid notifyDataSetChanged
and use the row based versions but as each time the toggle is pressed, it affects every other row, you do not really have a choice in this use case unless you keep track of the selected row.
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.VH> {
public static class MyData {
public boolean Selected = false;
public String Text;
public MyData(String text) {
Text = text;
}
}
public List<MyData> items = new ArrayList<>();
public TestAdapter() {
this.items.add(new MyData("Item 1"));
this.items.add(new MyData("Item 2"));
this.items.add(new MyData("Item 3"));
}
@Override
public TestAdapter.VH onCreateViewHolder(ViewGroup parent, int viewType) {
return new VH((
LayoutInflater.from(parent.getContext())
.inflate(R.layout.test_layout, parent, false))
);
}
@Override
public void onBindViewHolder(TestAdapter.VH holder, int position) {
final MyData itm = items.get(position);
holder.button.setChecked(itm.Selected);
holder.text.setText(itm.Text);
holder.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
for (MyData x: items){
x.Selected=false;
}
itm.Selected = true;
notifyDataSetChanged();
}
});
}
@Override
public int getItemCount() {
return items.size();
}
public class VH extends RecyclerView.ViewHolder {
ToggleButton button;
TextView text;
public VH(View itemView) {
super(itemView);
button = itemView.findViewById(R.id.toggle);
text = itemView.findViewById(R.id.text1);
}
}
}
test_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ToggleButton
android:id="@+id/toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
回答2:
Try setting OnCheckedChangeListener
instead of 'OnclickListener`
`button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// The toggle is enabled
} else {
// The toggle is disabled
}
}
});`
Android Doc : https://developer.android.com/guide/topics/ui/controls/togglebutton.html
回答3:
set on click listener in the onBindView and In the onClick method, first "turn off" all the toggle button by setting a parameter in the list model and then "turn on" the selected one if it is not selected.
@Override
public void onClick(View view) {
// clear all model values to isSelected false in the list
}
来源:https://stackoverflow.com/questions/44520390/disable-all-other-toggle-buttons-in-recycler-view-after-one-is-clicked