Home > Back-end >  prevent multiple checks from being selected in recycleview kotlin
prevent multiple checks from being selected in recycleview kotlin

Time:09-06

I'm having problems with the following case, I have my list of questions with their respective check boxes, what I can't understand is why when I click check on "Yes" other boxes are checked, does anyone know why this anomaly happens.

This is the "yes" frame problem in question 1 and it is marked in question 8, 14 and so on randomly.

enter image description here

enter image description here

This is my structure.xml that contains the checkboxes

<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:animateLayoutChanges="true"
app:cardCornerRadius="2dp"
app:cardElevation="4dp"
app:cardUseCompatPadding="true">
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:animateLayoutChanges="true"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@ id/icosemaforo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

            android:src="@drawable/ic_android" />

    </RelativeLayout>

    <LinearLayout
        android:id="@ id/contenedor_categoria1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
       android:layout_gravity="right"
        android:orientation="vertical"
        >
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >
            <TextView
                android:id="@ id/txtnumeropregunta"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:layout_alignParentTop="true"
                android:text="N°"
                android:textSize="14sp"
                android:textStyle="bold" />

            <TextView
                android:id="@ id/txtpreguntas"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:layout_marginTop="5dp"
                android:layout_marginEnd="20dp"
                android:layout_toStartOf="@ id/contenedorcheck"
                android:textSize="14sp"
                android:layout_toEndOf="@ id/txtnumeropregunta"
                android:textStyle="bold"
                android:text="Preguntas" />

            <LinearLayout
                android:id="@ id/contenedorcheck"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:layout_alignParentRight="true"
                android:layout_alignParentEnd="true"
                android:paddingEnd="20dp"
                >
                <CheckBox
                    android:id="@ id/chbksi"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"

                    android:text="@string/check_si" />
                <CheckBox
                    android:id="@ id/chbkIVSS"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"
                    android:visibility="gone"
                    android:text="@string/check_IVSS" />
                <CheckBox
                    android:id="@ id/chbkFSERV"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"
                    android:visibility="gone"
                    android:text="@string/check_freserv" />
                <CheckBox
                    android:id="@ id/chbkno"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"

                    android:layout_marginEnd="10dp"
                    android:text="@string/check_no" />
                <CheckBox
                    android:id="@ id/chbkfmano"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:visibility="gone"
                    android:layout_marginEnd="10dp"
                    android:text="@string/check_fredmano" />
                <CheckBox
                    android:id="@ id/chbkDSS"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:visibility="gone"
                    android:layout_marginEnd="10dp"
                    android:text="@string/check_DSS" />

                <CheckBox
                    android:id="@ id/chbkna"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:visibility="gone"
                    android:layout_marginEnd="10dp"
                    android:text="@string/check_na" />
            </LinearLayout>

        </RelativeLayout>

    </LinearLayout>
</LinearLayout>

</androidx.cardview.widget.CardView>

And this is my adapter.tk where I hide and show some custom boxes

class preusoadapter(private val listpreguntaspreuso: ArrayList<epreguntas>) : RecyclerView.Adapter<PreUsoViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PreUsoViewHolder {
    val layoutInflater = LayoutInflater.from(parent.context)
    return PreUsoViewHolder(layoutInflater.inflate(R.layout.activity_estructura_listapreuso, parent, false))
}

override fun onBindViewHolder(holder: PreUsoViewHolder, position: Int) {
   val item = listpreguntaspreuso[position]
    holder.render(item)

holder.itemView.chbksi.isChecked = item.checkvalor != false

    if (position == 2)
    {
        holder.itemView.chbkno.visibility = View.GONE
        holder.itemView.chbksi.visibility = View.GONE
        holder.itemView.chbkIVSS.visibility = View.VISIBLE
        holder.itemView.chbkDSS.visibility = View.VISIBLE
    }else if (position == 6){
        holder.itemView.chbkFSERV.visibility = View.VISIBLE
        holder.itemView.chbkfmano.visibility = View.VISIBLE
        holder.itemView.chbkno.visibility = View.GONE
        holder.itemView.chbksi.visibility = View.GONE

    }else if (position == 14){
        holder.itemView.chbkna.visibility = View.VISIBLE
    }else if (position == 18){
        holder.itemView.chbkna.visibility = View.VISIBLE
    }else  if (position == 22){
        holder.itemView.chbkna.visibility = View.VISIBLE
    }else   if (position == 25){
        holder.itemView.chbkna.visibility = View.VISIBLE
    }
    else{

        holder.itemView.chbkno.visibility = View.VISIBLE
        holder.itemView.chbksi.visibility = View.VISIBLE
        holder.itemView.chbkna.visibility = View.GONE
        holder.itemView.chbkIVSS.visibility = View.GONE
        holder.itemView.chbkDSS.visibility = View.GONE
        holder.itemView.chbkFSERV.visibility = View.GONE
        holder.itemView.chbkfmano.visibility = View.GONE
    }

}

override fun getItemCount(): Int = listpreguntaspreuso.size

this is my class equestions(epreguntas)

 class epreguntas(
    var id_pregunta: String,
    var num_pregunta: String,
    var pregunta : String,
    var icono_estado: String,
    var checkvalor: Boolean

) {


}

any ideas on how to handle these events and prevent it from randomly checking other boxes.

CodePudding user response:

If you want some checked state for your list items, you need to do three things:

  • store the checked state for the items, e.g. in the data itself, or (better) some data structure in the adapter
  • add a listener on your checkboxes that stores the checked/unchecked state for the current item
  • read that checked state in onBindViewHolder (where you're setting up a ViewHolder to display the current item) and check/uncheck the box as appropriate

I looked at your original question (before the edit) and I see you've added a checked boolean (checkvalor) to your Epreguntas data object, to store whether that item is checked or not. Personally I wouldn't do that - I feel like the checked state is a property of the list and not the data itself. So I'd store the checked state in a separate Set of all the checked position Ints, or a SparseBooleanArray where each index holds the checked state for position. But you can store it in the data object if you like!

So now you have somewhere to store the checked state, you need to set it when the checkbox is clicked, and read it when displaying an item.

You can set it with a click listener - I prefer this to an OnCheckedChangedListener because it only fires when the user taps it, and not when you set its checked state:

// I prefer setting the click listener in the ViewHolder class, but just to make things simple
override fun onBindViewHolder(holder: PreUsoViewHolder, position: Int) {
    val item = listpreguntaspreuso[position]

    holder.yourCheckBox.setOnClickListener {
        // toggle the checked state
        item.checkvalor = !item.checkvalor
        // update the display
        notifyItemChanged(position)
    }

Now your state changes in your item when the checkbox is clicked, so this line should work now:

holder.itemView.chbksi.isChecked = item.checkvalor != false

which you can just write as holder.itemView.chbksi.isChecked = item.checkvalor btw


A problem with storing your checked state in the data like this, is you have to persist it. If your Activity gets destroyed (e.g. during a rotation) or your whole app is recreated after being in the background, do you have those checkvalor values stored somewhere? Or will the data be recreated, with all the checkvalor values set to false?

If you store them in something like a SparseBooleanArray instead

// create a checked state lookup
private val checked = SparseBooleanArray(listpreguntaspreuso.size)

// read the checked state for an item
val isChecked = checked[position]

// toggle the checked state
checked[position] != checked[position]

then you can easily store that state when the parent Activity or Fragment hits onStop or onSaveInstanceState, and restore it when the parent is recreated. I've outlined that here if you want to look into it

  • Related