androidkotlinandroid-checkbox

How to select multiple checkboxes using one checkbox in android kotlin?


Here is my activity code:-

class SelectCoursesActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_select_courses)

        all_courses.setOnCheckedChangeListener { _, _ ->
            if (all_courses.isChecked) {
                scienceCourses()
                artsCourses()
                commerceCourses()
                all_science.isChecked = true
                all_arts.isChecked = true
                all_commerce.isChecked = true
            } else {
                scienceCourses()
                artsCourses()
                commerceCourses()
                all_science.isChecked = false
                all_arts.isChecked = false
                all_commerce.isChecked = false
            }
        }


        all_science.setOnCheckedChangeListener { _, _ ->
            all_courses.isChecked =
                all_science.isChecked && all_arts.isChecked && all_commerce.isChecked
        }

        all_arts.setOnCheckedChangeListener { _, _ ->
            all_courses.isChecked =
                all_science.isChecked && all_arts.isChecked && all_commerce.isChecked
        }

        all_commerce.setOnCheckedChangeListener { _, _ ->
            all_courses.isChecked =
                all_science.isChecked && all_arts.isChecked && all_commerce.isChecked
        }
    }

    private fun commerceCourses() {
        all_commerce.setOnCheckedChangeListener { _, _ ->
            if (all_commerce.isChecked) {
                accountancy.isChecked = true
                businessStudies.isChecked = true
                physicalEducation.isChecked = true
            } else {
                accountancy.isChecked = false
                businessStudies.isChecked = false
                physicalEducation.isChecked = false
            }
        }

        accountancy.setOnCheckedChangeListener { _, _ ->
            all_commerce.isChecked =
                accountancy.isChecked && businessStudies.isChecked && physicalEducation.isChecked
        }

        businessStudies.setOnCheckedChangeListener { _, _ ->
            all_commerce.isChecked =
                accountancy.isChecked && businessStudies.isChecked && physicalEducation.isChecked
        }

        physicalEducation.setOnCheckedChangeListener { _, _ ->
            all_commerce.isChecked =
                accountancy.isChecked && businessStudies.isChecked && physicalEducation.isChecked
        }
    }

    private fun artsCourses() {
        all_arts.setOnCheckedChangeListener { _, _ ->
            if (all_arts.isChecked) {
                economics.isChecked = true
                history.isChecked = true
                politicalScience.isChecked = true
            } else {
                economics.isChecked = false
                history.isChecked = false
                politicalScience.isChecked = false
            }
        }

        economics.setOnCheckedChangeListener { _, _ ->
            all_arts.isChecked =
                economics.isChecked && history.isChecked && politicalScience.isChecked
        }

        history.setOnCheckedChangeListener { _, _ ->
            all_arts.isChecked =
                economics.isChecked && history.isChecked && politicalScience.isChecked
        }

        politicalScience.setOnCheckedChangeListener { _, _ ->
            all_arts.isChecked =
                economics.isChecked && history.isChecked && politicalScience.isChecked
        }
    }

    private fun scienceCourses() {
        all_science.setOnCheckedChangeListener { _, _ ->
            if (all_science.isChecked) {
                physics.isChecked = true
                chemistry.isChecked = true
                math.isChecked = true
            } else {
                physics.isChecked = false
                chemistry.isChecked = false
                math.isChecked = false
            }
        }

        physics.setOnCheckedChangeListener { _, _ ->
            all_science.isChecked = physics.isChecked && chemistry.isChecked && math.isChecked
        }

        chemistry.setOnCheckedChangeListener { _, _ ->
            all_science.isChecked = physics.isChecked && chemistry.isChecked && math.isChecked
        }

        math.setOnCheckedChangeListener { _, _ ->
            all_science.isChecked = physics.isChecked && chemistry.isChecked && math.isChecked
        }
    }
}

here is activity xml code:-

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_margin="20dp"
    tools:context=".SelectCoursesActivity">

    <CheckBox
        android:id="@+id/all_courses"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/all_courses"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/science"
        android:textSize="20sp"
        android:textStyle="bold"/>

    <CheckBox
        android:id="@+id/all_science"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/all"/>

    <CheckBox
        android:id="@+id/physics"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/physics"/>

    <CheckBox
        android:id="@+id/math"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/math"/>

    <CheckBox
        android:id="@+id/chemistry"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/chemistry"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/arts"
        android:textSize="20sp"
        android:textStyle="bold"/>

    <CheckBox
        android:id="@+id/all_arts"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/all"/>

    <CheckBox
        android:id="@+id/economics"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/economics"/>

    <CheckBox
        android:id="@+id/history"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/history"/>

    <CheckBox
        android:id="@+id/politicalScience"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/politicalScience"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/science"
        android:textSize="20sp"
        android:textStyle="bold"/>

    <CheckBox
        android:id="@+id/all_commerce"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/all"/>

    <CheckBox
        android:id="@+id/accountancy"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/accountancy"/>

    <CheckBox
        android:id="@+id/businessStudies"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/businessStudies"/>

    <CheckBox
        android:id="@+id/physicalEducation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/physicalEducation"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:backgroundTint="@null"
        android:background="@drawable/circular_button"
        android:textColor="@color/red_primary"
        android:text="@string/save"/>

</LinearLayout>

I am trying to make to activity that if:- 1)all courses checkbox is selected then all other checkboxes should be checked and vice versa.

2)all science button is checked then all other subjects buttons should be selected and vice versa. Same for all other subjects as well.

3)if any course button is not checked then all courses button should also not be checked. Same for all subjects as well.

Now I am able to check and uncheck using all courses button. But when I am unchecking any course button I am it is not unchecking all courses button.

When any course button is checked and when I uncheck any subject it unchecks all the subjects in that course. I want to uncheck only that course checkbox and that subjet all other courses should remain checked.


Solution

  • Instead of direct checkboxes use recyclerView in this way:-

    activity code:-

    lateinit var recyclerView: RecyclerView
    lateinit var adapter: CheckboxAdapter
    lateinit var list3: List<RowModel>
    lateinit var list1: List<RowModel>
    lateinit var list2: List<RowModel>
    lateinit var list4: List<RowModel>
    lateinit var list: List<RowModel>
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_select_courses)
    
        recyclerView = findViewById(R.id.trail_rv)
    
        list1 = listOf(
            RowModel(RowType.TopHeader, "", "", "", false)
        )
    
        list2 = listOf(
            RowModel(RowType.Course, "", "", "Science", false),
            RowModel(RowType.SubjectRow, "Physics", "", "Science", false),
            RowModel(RowType.Dummy, "Physics", "Physics", "Science", false),
            RowModel(RowType.SubjectRow, "Math", "", "Science", false),
            RowModel(RowType.Dummy, "Math", "Math", "Science", false),
            RowModel(RowType.SubjectRow, "Chemistry", "", "Science", false),
            RowModel(RowType.Dummy, "Chemistry", "Chemistry", "Science", false)
        )
    
        list3 = listOf(
            RowModel(RowType.Course, "", "", "Arts", false),
            RowModel(RowType.SubjectRow, "Economics", "", "Arts", false),
            RowModel(RowType.Dummy, "Economics", "Economics", "Arts", false),
            RowModel(RowType.SubjectRow, "History", "", "Arts", false),
            RowModel(RowType.Dummy, "History", "History", "Arts", false),
            RowModel(RowType.SubjectRow, "Political Science", "", "Arts", false),
            RowModel(RowType.Dummy, "Political Science", "Political Science", "Arts", false)
        )
    
        list4 = listOf(
            RowModel(RowType.Course, "", "", "Commerce", false),
            RowModel(RowType.SubjectRow, "Accountancy", "", "Commerce", false),
            RowModel(RowType.Dummy, "Accountancy", "Accountancy", "Commerce", false),
            RowModel(RowType.SubjectRow, "Business Studies", "", "Commerce", false),
            RowModel(RowType.Dummy, "Business Studies", "Business Studies", "Commerce", false),
            RowModel(RowType.SubjectRow, "Physical Education", "", "Commerce", false),
            RowModel(RowType.Dummy, "Physical Education", "Physical Education", "Commerce", false)
        )
    
        list = list1 + list2 + list4 + list3
    
        adapter = CheckboxAdapter(this, list)
        adapter.setList(list)
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(this)
    
        findViewById<Button>(R.id.showTextBtn).setOnClickListener {
            val checkboxesValue: String = selectedCheckboxes.joinToString(separator = ";\n")
            findViewById<TextView>(R.id.ShowTextView).text = checkboxesValue
        }
    
        findViewById<Button>(R.id.clearTextBtn).setOnClickListener {
            selectedCheckboxes.clear()
            adapter.setList(list)
        }
    
        }
    }
    

    adapter code:-

    class CheckboxAdapter(
        private val context: Context,
        var productList: List<RowModel>,
    ) : RecyclerView.Adapter<CheckboxAdapter.TableViewHolder>() {
    
    
        override fun onBindViewHolder(holder: TableViewHolder, position: Int) {
    
            val item = productList[position]
    
            holder.checkBox.setOnCheckedChangeListener(null)
            holder.checkBox.isChecked = item.isChecked
    
            val params: ViewGroup.MarginLayoutParams =
                holder.checkBox.layoutParams as ViewGroup.MarginLayoutParams
    
            when (item.rowType) {
                RowType.TopHeader -> {
                    holder.checkBox.text = "All Courses"
                    holder.checkBox.visibility = View.VISIBLE
                    holder.checkBox.typeface = Typeface.DEFAULT_BOLD
                    params.setMargins(0, 0, 0, 0)
                    holder.checkBox.layoutParams = params
    
                }
                RowType.Course -> {
    
                    holder.checkBox.visibility = View.VISIBLE
                    holder.checkBox.text = item.course
                    holder.checkBox.typeface = Typeface.DEFAULT_BOLD
                    params.setMargins(20, 0, 0, 0)
                    holder.checkBox.layoutParams = params
    
                }
                RowType.SubjectRow -> {
    
                    holder.checkBox.visibility = View.VISIBLE
                    holder.checkBox.text = item.subjectName
                    holder.checkBox.typeface = Typeface.DEFAULT
                    params.setMargins(convertDpToPixel(40f, context).toInt(), 0, 0, 0)
                    holder.checkBox.layoutParams = params
                }
                RowType.Dummy -> {
    
                    holder.checkBox.visibility = View.GONE
                    holder.checkBox.text = item.subjectName
                    holder.checkBox.typeface = Typeface.DEFAULT
                    params.setMargins(convertDpToPixel(60f, context).toInt(), 0, 0, 0)
                    holder.checkBox.layoutParams = params
                }
            }
    
            holder.checkBox.setOnCheckedChangeListener { _, isChecked ->
                if (item.isChecked != isChecked) {
                    item.isChecked = isChecked
    
                    when (item.rowType) {
                        RowType.TopHeader -> {
                            val indexList = mutableListOf<Int>()
                            productList.filter { it.rowType != RowType.TopHeader }.forEach {
                                it.isChecked = isChecked
                                indexList.add(productList.indexOf(it))
                            }
                            indexList.forEach {
                                notifyItemChanged(it)
                            }
                        }
                        RowType.Course -> {
                            val indexList = mutableListOf<Int>()
                            productList.filter { it.rowType == RowType.SubjectRow && it.course == item.course }
                                .forEach {
                                    it.isChecked = isChecked
                                    indexList.add(productList.indexOf(it))
                                }
                            productList.filter { it.rowType == RowType.Dummy && it.course == item.course }
                                .forEach {
                                    it.isChecked = isChecked
                                    indexList.add(productList.indexOf(it))
                                }
                            indexList.forEach {
                                notifyItemChanged(it)
                            }
                            isAllItemsSameStatus() //for header
                        }
                        RowType.SubjectRow -> {
                            val indexList = mutableListOf<Int>()
                            productList.filter { it.rowType == RowType.Dummy && it.subjectName == item.subjectName }
                                .forEach {
                                    it.isChecked = isChecked
                                    indexList.add(productList.indexOf(it))
                                }
                            indexList.forEach {
                                notifyItemChanged(it)
                            }
                            isAllItemsSameStatus()
                        }
                    }
                }
            }
    
    
            when (item.rowType) {
                RowType.Course -> {
                    if (holder.checkBox.isChecked)
                        selectedCheckboxes.add(holder.checkBox.text.toString())
                    if (!holder.checkBox.isChecked) {
                        selectedCheckboxes.remove(holder.checkBox.text.toString())
                    }
                }
                RowType.Dummy -> {
                    if (holder.checkBox.isChecked)
                        selectedCheckboxes.add(holder.checkBox.text.toString())
                    if (!holder.checkBox.isChecked) {
                        selectedCheckboxes.remove(holder.checkBox.text.toString())
                    }
                }
            }
        }
    
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TableViewHolder {
            return TableViewHolder(
                LayoutInflater.from(context).inflate(
                    R.layout.checkbox,
                    parent,
                    false
                )
            )
        }
    
        class TableViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    
            val checkBox: CheckBox = itemView.findViewById(R.id.Checkbox)
    
        }
    
        override fun getItemCount() = productList.size
    
    
        fun setList(profiles: List<RowModel>) {
            productList = profiles
            notifyDataSetChanged()
        }
    
        private fun isAllItemsSameStatus(cat: String? = null) {
    
            val row: RowModel
            var isChecked: Boolean = true
            var position: Int = 0
    
            if (cat != null) {
                val catRow = productList.find { it.rowType == RowType.Course && it.course == cat }
                catRow?.let {
                    val subList =
                        productList.filter { it.course == it.course && it.rowType == RowType.SubjectRow }
                    isChecked = subList.filter { it.isChecked }.size == subList.size
                    position = productList.indexOf(catRow)
                }
                if (catRow == null)
                    return
                else
                    row = catRow
            } else {
                row = productList[0]
                isChecked =
                    productList.filter { it.rowType != RowType.TopHeader && it.isChecked }.size == productList.size - 1
                position = 0
            }
    
            updateHeader(row, isChecked, position)
        }
    
        private fun isAllSubjectItemsSameStatus(cat: String? = null) {
    
            val row: RowModel
            var isChecked: Boolean = true
            var position: Int = 0
    
            if (cat != null) {
                val catRow =
                    productList.find { it.rowType == RowType.SubjectRow && it.subjectName == cat }
                catRow?.let {
                    val subList =
                        productList.filter { it.subjectName == it.subjectName && it.rowType == RowType.Dummy }
                    isChecked = subList.filter { it.isChecked }.size == subList.size
                    position = productList.indexOf(catRow)
                }
                if (catRow == null)
                    return
                else
                    row = catRow
            } else {
                row = productList[0]
                isChecked =
                    productList.filter { it.rowType != RowType.TopHeader && it.isChecked }.size == productList.size - 1
                position = 0
            }
    
            updateHeader(row, isChecked, position)
        }
    
    
        private fun updateHeader(item: RowModel, isChecked: Boolean, position: Int) {
            if (item.isChecked != isChecked) // no need to update if no change
            {
                item.isChecked = isChecked
                notifyItemChanged(position)
    
            }
        }
    
        private fun convertDpToPixel(dp: Float, context: Context): Float {
            return dp * (context.resources
                .displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
        }
    
        companion object {
            var selectedCheckboxes: ArrayList<String> = ArrayList()
        }
    
    }
    

    Model data class code:-

    data class SubjectRowModel (
        val SubjectRowType: SubjectRowType,
        val subjectName: String,
        val dummyName: String,
        val course: String,
        var isChecked: Boolean = true)
    
    enum class SubjectRowType(val id : Int) {
    
        TopHeader(1),
        Course(2),
        SubjectRow(3),
        Dummy(4);
    
    }