javaandroidandroid-recyclerviewandroid-switch

How to select only one switch in a recycler view?


I have come across a problem while trying to add a switch to each element of my recycler adapter. What I want to achieve is to have only ONE switch selected at a time, so whenever I check a switch every other switch should automatically be unchecked.

This is the recycler adapter code I am currently using:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {

    private final DomainAdapter DA = DomainAdapter.getInstance();
    private final ArrayList<ArrayList<String>> list;
    private String selected;


    public RecyclerAdapter(ArrayList<ArrayList<String>> list, String selected) {
        this.list = list;
        this.selected = selected;
    }


    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        View view = layoutInflater.inflate(R.layout.list_element, parent, false);
        return new ViewHolder(view);
    }


    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

        if (list.get(position).get(0).equals(selected)) holder.switchButton.setChecked(true);
        else holder.switchButton.setChecked(false);

        holder.switchButton.setOnCheckedChangeListener((toggleButton, isChecked) -> {
            if (isChecked) {
                try {
                    DA.select(list.get(position).get(0));
                } catch (NoSuchMethodException ignore) {}
            }
            else {
                
            }

        });

    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {

        Switch switchButton;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            switchButton = itemView.findViewById(R.id.switchButton);
        }
    }

}

I would really appreciate it if someone could tell me what I'm doing wrong.

Thank you!


Solution

  • Your logic is a bit incorrect.

    You do :

    if (list.get(position).get(0).equals(selected)) holder.switchButton.setChecked(true);
        else holder.switchButton.setChecked(false);
    

    And this invokes the checkedChange listener that you set a line later, in the next iteration after it has been set for the first time.

    Remove the checkChangeListener and set a click listener instead.

    Also, set the click listener in the onCreateViewHolder rather than in the onBindViewHolder

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        View view = layoutInflater.inflate(R.layout.list_element, parent, false);
        ViewHolder vh = new ViewHolder(view);
        vh.switchButton.setOnClickListener( new OnClickListener() {
          @Override
          public void onClick(View view) {
              setItemSelected(vh.getAdapterPosition());
          }
         });
    
        return vh;
    }
    
    
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) 
     {
        boolean isSelected = list.get(position).get(0).equals(selected);
        holder.switchButton.setChecked(isSelected);
    
    }
    
    private void setItemSelected(int position) {
         DA.select(list.get(position).get(0));
         selected = list.get(position).get(0);
         notifyDataSetChanged();
    }