Check box in recyclerview is automatically unchecked when scrolling in android - android

I have created a view using recyclerview adapter for listing students. My problem is that when i am scrolling the view all the checked checkboxes are automatically unchecked. Which means the states are changing.How to overcome the issue
Here i shared my code. Please check and suggest a solution. Thanks in advance.
class IndividualStudentSelectAdapter(private val context: Context,
private var students: List<IndividualStudentBean>,
private val checkBox1: CheckBox,
private val individualStudentSelectionListener: IndividualStudentSelectionListener
)
: RecyclerView.Adapter<IndividualStudentSelectAdapter.ViewHolder>(){
companion object {
val TAG: String = IndividualStudentSelectAdapter::class.java.simpleName
}
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): IndividualStudentSelectAdapter.ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.individual_student, p0, false))
}
override fun getItemCount(): Int {
return students.size
}
override fun onBindViewHolder(p0: ViewHolder, p1: Int) {
val user = students.get(p1)
p0.bindView(p1)
p0.binding.individualStudentBean = students[p1]
if (user.getSelected()==true) {
p0.checkbox2.isChecked = true
} else {
p0.checkbox2.isChecked = false
}
p0.checkbox2.setOnCheckedChangeListener { buttonView, isChecked ->
if(isChecked)
{
// val individualStudentBean = IndividualStudentBean(user.empid,"","")
Log.d("admnos",user.id)
individualStudentSelectionListener.addDatas(user.id)
user.setSelected(true)
}else{
individualStudentSelectionListener.removeDatas(user.id)
user.setSelected(false)
}
}
checkBox1.setOnCheckedChangeListener {
buttonView, isChecked ->
if (isChecked){
for (item in students)
{
p0.checkbox2.isChecked = true
item.setSelected(true)
notifyDataSetChanged()
}
}else{
for (item in students) {
p0.checkbox2.isChecked = false
item.setSelected(false)
notifyDataSetChanged()
}
}
}
}
fun updateDataset(students: List<IndividualStudentBean>) {
this.students = students
notifyDataSetChanged()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var binding: IndividualStudentBinding = DataBindingUtil.bind(itemView)!!
val checkbox2 = itemView.findViewById(R.id.cb_student) as CheckBox
fun bindView(position: Int) {
// this.setIsRecyclable(false)
binding.individualStudentBean = students[position]
itemView.setOnClickListener {
//students[position].selected = itemView.cb_student.isChecked
if (context is IndividualStudentSelectActivity) {
//context.onStudentSelected()
}
if (context is IndividualStudentSelectActivity) {
//context.onStudentSelected()
}
}
}
}
}

add a Property called isChecked (the name depends on your choice) to your Student data class, then add this code in bindView method
checkbox2.isChecked = students[adapterPosition].isChecked
checkbox2.setOnCheckedChangeListener { _, isChecked ->
students[adapterPosition].isChecked = isChecked
}

Related

How to select all checkboxes in recyclerview on click?

I display several items in the recyclerview, each item has its own checkbox, I want to select the necessary ones and delete them. I did this part and it works well, but I can’t do select all items, please tell me what’s wrong.
Here is my code:
initRecyclerView
private fun initRecyclerView() {
binding.recyclerView.setHasFixedSize(true)
val adapter = AdapterList(requireActivity(), arrayList)
binding.recyclerView.layoutManager = LinearLayoutManager(requireActivity().applicationContext, LinearLayoutManager.VERTICAL, false)
binding.recyclerView.adapter = adapter
}
My function for checkbox in fragment:
binding.allCheckBox.setOnClickListener {
if (isAllSelect) {
AdapterList().unselectAll()
isAllSelect = false
} else {
AdapterList().selectAll()
isAllSelect = true
}
}
My adapter
class AdapterList(private val activity: Activity? = null, private var recyclerList: ArrayList<Info>? = null) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
return (holder as ViewHolder).bind(recyclerList!![position])
}
override fun getItemCount(): Int {
return recyclerList!!.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return ViewHolder(LayoutInflater.from(activity).inflate(R.layout.item_layout, parent, false))
}
private var isSelectedAll = false
#SuppressLint("NotifyDataSetChanged")
fun selectAll() {
isSelectedAll = true
notifyDataSetChanged()
}
#SuppressLint("NotifyDataSetChanged")
fun unselectAll() {
isSelectedAll = false
notifyDataSetChanged()
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private var binding: ItemLayoutBinding = ItemLayoutBinding.bind(view)
#SuppressLint("NotifyDataSetChanged")
fun bind(list: Info) {
binding.apply {
cardIcon.setImageDrawable(list.icon)
cardName.text = list.name
cardCheckBox.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
recyclerList!![position].checked = isChecked
notifyDataSetChanged()
}
cardCheckBox.isChecked = isSelectedAll
}
}
}
}
Now it crashes on clicking on the checkbox in cardview because of the line
cardCheckBox.isChecked = isSelectedAll
in Adapter
Tried to do as described here but does not work Select all checkboxes in RecyclerView
If I do so
binding.allCheckBox.setOnClickListener {
if (isAllSelect) {
for (list in arrayList) {
list.checked = false
}
isAllSelect = false
} else {
for (list in arrayList) {
list.checked = true
}
isAllSelect = true
}
}
By clicking on the delete button, I see that the data is correct, but the checkbox in the recyclerview is not updated (notifyDataSetChanged() does not work?), and I'm not sure if this approach is correct

On RecyclerView scroll random checkbox selected in kotlin

*Note: There are solutions for this issue in stackoverflow but all are written in java
In Recyclerview implemented checkbox OnCheckedChangeListener as follows, problem is when i scroll recyclerview then random checkbox is selected.
class ScSerialAdapter(
private val scSerialNumberList: List<String>,
private val selectedSerialNumberList: ArrayList<String> = arrayListOf<String>()
) :
RecyclerView.Adapter<ScSerialAdapter.ScLocationListViewHolder>() {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ScLocationListViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.stock_serials_list_item, parent, false)
return ScLocationListViewHolder(itemView)
}
override fun onBindViewHolder(holder: ScLocationListViewHolder, position: Int) {
holder.cbSelected.isChecked = false
val currentSerialNo = this.scSerialNumberList[position]
for (item in selectedSerialNumberList) {
if (item == currentSerialNo) {
holder.cbSelected.isChecked = true
break
}
}
holder.cbSelected.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
selectedSerialNumberList.add(this.scSerialNumberList[position])
Log.e("selectedSerialNumber",selectedSerialNumberList.size.toString())
} else {
Log.e("SelectedSerialNumber",selectedSerialNumberList.size.toString())
selectedSerialNumberList.remove(this.scSerialNumberList[position])
}
}
if (scSerialNumberList != null) {
holder.tvSerial.text = scSerialNumberList[position].toString()
} else {
holder.tvSerial.text = "-"
}
}
fun listOfSelectedValues(): List<String> {
return selectedSerialNumberList
}
override fun getItemCount(): Int {
return scSerialNumberList.size
}
inner class ScLocationListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val tvSerial: TextView = itemView.tv_serial
val cbSelected: CheckBox = itemView.cb_selected
}
}
You need to set the checkbox value every time the onBindViewHolder() get called with a new row in the RecyclerView
override fun onBindViewHolder(holder: PickListViewHolder, position: Int) {
if (selectedSerialNumberList.contains(this.scSerialNumberList[position])) {
holder.cbSelected.isChecked = true
} else {
holder.cbSelected.isChecked = false
}
holder.cbSelected.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
selectedSerialNumberList.add(this.scSerialNumberList[position])
} else {
selectedSerialNumberList.remove(this.scSerialNumberList[position])
}
}
}
UPDATE
Try to iterate on the list and check if the serial number exist.
override fun onBindViewHolder(holder: PickListViewHolder, position: Int) {
holder.cbSelected.isChecked = false
val currentSerialNo = this.scSerialNumberList[position]
for (item in selectedSerialNumberList) {
if (item == currentSerialNo) {
holder.cbSelected.isChecked = true
break
}
}
//...
}
In onBindViewHolder made following changes, It worked
override fun onBindViewHolder(holder: ScLocationListViewHolder, position: Int) {
holder.cbSelected.setOnCheckedChangeListener(null)
holder.cbSelected.isChecked = selectedSerialNumberList.contains(this.scSerialNumberList[position])
holder.cbSelected.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
selectedSerialNumberList.add(this.scSerialNumberList[position])
Log.e("selectedSerialNumber", selectedSerialNumberList.size.toString())
} else {
Log.e("SelectedSerialNumber", selectedSerialNumberList.size.toString())
selectedSerialNumberList.remove(this.scSerialNumberList[position])
}
}
if (scSerialNumberList != null) {
holder.tvSerial.text = scSerialNumberList[position].toString()
} else {
holder.tvSerial.text = "-"
}
}

chekbox always checking last item in recyclerview

i want to get item from checked checkbox in my recyclerview item, this my adapter
class SelectedListDateAdapter(var listDate: List<DateDay>, private val onItemCheckListener: OnItemCheckListener) :
RecyclerView.Adapter<SelectedListDateAdapter.SelectedListDateViewHolder>() {
lateinit var binding: ItemCheckBoxDateBinding
inner class SelectedListDateViewHolder(item: ItemCheckBoxDateBinding) : RecyclerView.ViewHolder(item.root) {
val checkBoxList = item.checkBox
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SelectedListDateViewHolder {
binding = ItemCheckBoxDateBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return SelectedListDateViewHolder(binding)
}
override fun onBindViewHolder(holder: SelectedListDateViewHolder, position: Int) {
holder.checkBoxList.setOnCheckedChangeListener(null)
holder.checkBoxList.isChecked = listDate[position].isSelected
holder.itemView.apply {
val currentItem = listDate[position]
binding.tvDateList.text = listDate[position].date
setOnClickListener {
binding.checkBox.isChecked = !binding.checkBox.isChecked
if (binding.checkBox.isChecked) {
binding.checkBox.setOnCheckedChangeListener { buttonView, isChecked ->
currentItem.isSelected = isChecked
}
onItemCheckListener.onItemCheck(currentItem)
} else {
binding.checkBox.setOnCheckedChangeListener { buttonView, isChecked ->
currentItem.isSelected = isChecked
}
onItemCheckListener.onItemUncheck(currentItem)
}
}
}
}
override fun getItemCount(): Int {
return listDate.size
}
}
im referring to this question get list of checked item to make that adapter
yes, it get the item and remove them but everytime i click an item in recyclerview it always check and uncheck the last item
i have checking this question CheckBox in RecyclerView keeps on checking different items but my result still the same, any help is appreciated
Maybe viewHolder reuse the previous item.Try to update listData, not currentItem.
And move the nested Listener
override fun onBindViewHolder(holder: SelectedListDateViewHolder, position: Int) {
holder.itemView.tvDateList.text = listDate[position].date
holder.checkBoxList.isChecked = listDate[position].isChecked
holder.checkBoxList.setOnClickListener {
listDate[position].isSelected = holder.checkBoxList.isChecked
}
holder.itemView.setOnClickListener {
holder.checkBoxList.isChecked = !holder.checkBoxList.isChecked
listDate[position].isSelected = holder.checkBoxList.isChecked
val currentItem = listDate[position]
if (holder.checkBoxList.isChecked) {
onItemCheckListener.onItemCheck(currentItem)
} else {
onItemCheckListener.onItemUncheck(currentItem)
}
}
}

RecyclerView OnCheckedChangeListener bug when click TabLayout

so I have TabLayout with RecyclerView, when I click the tab it reloads the RecyclerView with new sets of data, but I'm having a problem with onCheckedChangeListener.
When I change the tab it reloads the new set of data but it also triggers the onCheckedChangeListener too.
here's the code that I have
ADAPTER
class ProductAdapter(
private val product: ArrayList<ProductDataRs>
) : RecyclerView.Adapter<ProductAdapter.DataViewHolder>() {
var onItemClick: ((ProductDataRs) -> Unit)? = null
inner class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(productDataRs: ProductDataRs) {
itemView.text_view_product_name.text = productDataRs.name.toString()
itemView.text_view_description.text = productDataRs.description.toString()
itemView.text_view_price.text = "Php ${productDataRs.price.toString()}"
itemView.switch_product.isChecked = productDataRs.status != 0
itemView.switch_product.setOnCheckedChangeListener { compoundButton: CompoundButton, b: Boolean ->
onItemClick?.invoke(product[adapterPosition])
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
DataViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_product_layout, parent,
false
)
)
override fun getItemCount(): Int = product.size
override fun onBindViewHolder(holder: DataViewHolder, position: Int) {
holder.bind(product[position])
}
FRAGMENT
private fun setupUI() {
fragmentProductsBinding.recyclerViewProducts.layoutManager =
LinearLayoutManager(activity?.applicationContext)
productAdapter = ProductAdapter(arrayListOf())
fragmentProductsBinding.recyclerViewProducts.adapter = productAdapter
productAdapter.onItemClick = { product ->
Log.e("asd", "asd")
// updateProductStatus(product.id!!, if (product.status == 0) 1 else 0)
}
fragmentProductsBinding.tabLayoutProducts.addOnTabSelectedListener(object :
TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
var iterator = (data)?.iterator()
if (iterator != null) {
for ((index, rs) in iterator.withIndex()) {
if (index == tab.position) {
rs.products?.let { retrieveList(it) }
}
}
} else {
Log.e("ProductsFragment", "no data")
}
}
})
}
If you want to trigger it when it is on(isChecked) you should change your code to :
itemView.switch_product.setOnCheckedChangeListener { compoundButton: CompoundButton, b: Boolean ->
if(b) onItemClick?.invoke(product[adapterPosition])
}
If else you want to trigger it when it is off(unChecked) you should change your code to :
itemView.switch_product.setOnCheckedChangeListener { compoundButton: CompoundButton, b: Boolean ->
if(!b) onItemClick?.invoke(product[adapterPosition])
}
you can combine the TabLayout and viewPager2 and handle the recycler view in that fragment :
https://developer.android.com/guide/navigation/navigation-swipe-view-2
i did the similar thing on this project i leave it down below if you want more examples:
https://github.com/ErfanDP/Erfan_Delavari_HW12_Maktab36
at first enter random name that doesn't matter

Select only one check box ; RecyclerView; Kotlin

It's my code and I want to choose only one checkbox, and if another checkbox is selected I want that this convert in uncheked
class AuthorizationFormAdapter(lista: List<Procedures>?) : RecyclerView.Adapter<AuthorizationFormAdapter.ViewHolder>() {
val lista: List<Procedures>? = lista
lateinit var array: BooleanArray
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
val text: TextView? = null
val checkBox: CheckBox? = null
}
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.card_authform, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return lista!!.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.view.auth_name.text = lista!![position].name_procedure
holder.view.cb_auth.setOnClickListener {
if (holder.view.cb_auth.isChecked) {
holder.view.cb_auth.isSelected = true
} else if (!holder.view.cb_auth.isChecked) {
holder.view.cb_auth.isChecked = false
}
}
}
}
And Xml is only one checkBox and textView in my card
I will be very grateful with your help
You have to create a field in your Procedures to store the checked/unchecked state
var isChecked: Boolean = false
Then inside your adapter store lastCheckedPosition and unchecked when user select other.
class AuthorizationFormAdapter(lista: List<Procedures>?) : RecyclerView.Adapter<AuthorizationFormAdapter.ViewHolder>() {
var lastCheckedPosition: Int = 0
....
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val procedure = lista!![position]
holder.view.auth_name.text = procedure.name_procedure
holder.view.cb_auth.isChecked = procedure.is_checked
holder.view.cb_auth.setOnCheckedChangeListener { buttonView, isChecked ->
if(isChecked) {
lista!![lastCheckedPosition].is_checked = false
lastCheckedPosition = position
}
lista!![position].is_checked = isChecked
notifyDataSetChanged() // This is important to reload the list
}
}
}

Categories

Resources