Disable checkbox in Recyclerview

Asked

Viewed 246 times

1

Each item of a RecyclerView contains a Checkbox, and when selecting a checkbox would like to disable all other checkboxes.

I created a setOnCheckedChangeListener within the onBindViewHolder and I believe I should disable the other checkboxes within it after a checkbox is selected, making a for and ignoring the selected one. But I don’t know how to take each Recyclerview item and disable the checkbox.

Am I on the right track or should I implement otherwise? Is there a simple way to do this?

Summarizing my scenario, I have a list and want the user to select only one item, disabling the others after one is selected.

UPDATED:

Viewholder:

public class LocalRouteSelectionViewHolder extends RecyclerView.ViewHolder {

    public final TextView tvId;
    public final TextView tvDate;
    public final TextView tvTarget;
    public final TextView tvAmount;
    public final CheckBox cbRouteSelect;

    public LocalRouteSelectionViewHolder(View view) {
        super(view);
        tvId = (TextView) view.findViewById(R.id.textview_route_selection_id);
        tvDate = (TextView) view.findViewById(R.id.textview_route_selection_date);
        tvTarget = (TextView) view.findViewById(R.id.textview_route_selection_target);
        tvAmount = (TextView) view.findViewById(R.id.textview_route_selection_amount);
        cbRouteSelect = (CheckBox) view.findViewById(R.id.checkbox_route_select);
    }

}

Adapter:

public class LocalRouteListSelectionAdapter extends RecyclerView.Adapter {

    private List<Route> routes;
    private Context context;
    Route route;

    public LocalRouteListSelectionAdapter(List<Route> routes, Context context) {
        this.routes = routes;
        this.context = context;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context)
                .inflate(R.layout.item_localroute_selection, parent, false);

        LocalRouteSelectionViewHolder holder = new LocalRouteSelectionViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
        LocalRouteSelectionViewHolder holder = (LocalRouteSelectionViewHolder) viewHolder;
        route = routes.get(position) ;

        String year = route.getDate().substring(0,4);
        String month = route.getDate().substring(5, 7);
        String day = route.getDate().substring(8, 10);
        String date = day + "/" + month + "/" + year;

        holder.tvId.setText(String.format("%03d", route.getId()));
        holder.tvDate.setText(date);
        holder.tvTarget.setText(route.getTarget());
        holder.tvAmount.setText(String.valueOf(route.getAmount()));

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Route route = routes.get(position);
                Context context = view.getContext();
                Intent intent = new Intent(context, RouteDetailsActivity.class);
                intent.putExtra("ROUTE", route);
                context.startActivity(intent);
            }
        });

        holder.cbRouteSelect.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                // implementar aqui
            }
        });
    }

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

}
  • That’s right. Show the code you already have. I only recommend changing checkbox to radio button, which is the appropriate interface element for single selection.

  • Initially I tried to use Radiobutton, but I saw that to work it needs to be exactly below the Radiogroup, and in my case there is a Radiobutton in each item, only. Maybe putting Radiogroup in the Activity layout and Recyclerview in it, but I don’t know. I updated the post with the code.

  • 1

    I just saw that since Recyclerview reuses views, the solution would be to flag objects and check this flag to select and deselect. https://stackoverflow.com/a/37618659/6286312

1 answer

1


I did something similar in a project of mine using Radio Button, which I believe is also the most appropriate for your case (checkboxes imply more than one selection). I’ll put the code to my Adapter:

public class SingleHistoryConfigureAdapter extends
        RecyclerView.Adapter<SingleHistoryConfigureAdapter.HistoryConfigWidgetViewHolder> {

    final private OnItemClickListener mOnClickListener;

    private Cursor mCursor;
    private Context mContext;
    private static int sItemSelected = -1;
    public static final int INVALID_HISTORY_ID = -1;

    public interface OnItemClickListener {
        void onListItemClick(long historyId);
    }

    public SingleHistoryConfigureAdapter(@NonNull Context context, OnItemClickListener listener) {
        mContext = context;
        mOnClickListener = listener;
    }

    public void swapCursor(Cursor newCursor) {
        mCursor = newCursor;
        notifyDataSetChanged();
    }

    public void invalidateSelection() {
        sItemSelected = -1;
    }

    public long getSelectedHistoryId() {
        return (mCursor != null && mCursor.moveToPosition(sItemSelected))
                ? mCursor.getLong(HistoryGridFragment.INDEX_HISTORY_ID)
                : INVALID_HISTORY_ID;
    }

    @Override
    public HistoryConfigWidgetViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        int layoutIdForListItem = R.layout.single_history_widget_item;
        LayoutInflater inflater = LayoutInflater.from(mContext);

        View view = inflater.inflate(layoutIdForListItem, viewGroup, false);
        return new HistoryConfigWidgetViewHolder(view);
    }

    @Override
    public void onBindViewHolder(HistoryConfigWidgetViewHolder holder, int position) {
        mCursor.moveToPosition(position);
        String title = Jsoup.parse(mCursor.getString(HistoryGridFragment.INDEX_HISTORY_TITLE)).text();
        holder.historyRadio.setText(title);
        holder.historyRadio.setChecked(sItemSelected == position);
    }

    @Override
    public int getItemCount() {
        return (mCursor == null) ? 0 : mCursor.getCount();
    }

    public class HistoryConfigWidgetViewHolder extends RecyclerView.ViewHolder
            implements View.OnClickListener {

        public RadioButton historyRadio;

        public HistoryConfigWidgetViewHolder(View itemView) {
            super(itemView);
            historyRadio = (RadioButton) itemView.findViewById(R.id.option_radio);
            itemView.setOnClickListener(this);
            historyRadio.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            mCursor.moveToPosition(getAdapterPosition());
            mOnClickListener.onListItemClick(mCursor.getLong(HistoryGridFragment.INDEX_HISTORY_ID));

            sItemSelected = getAdapterPosition();
            notifyItemRangeChanged(0, getItemCount());
        }
    }
}

Quick explanation:

1) The selected item I chose to store in a static variable (sItemSelected) to persist in case of Activity destruction

2) The above variable is set in onClick() Radio (according to the position of the Adapter), where it also forces Recyclerview to reload

3) in the onBindViewHolder() i force Radio selection on item whose position in Adapter is the same as variable sItemSelected.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.