I'm trying to check multiple items in RecyclerView
and delete them but unable to delete after checking CheckBox
in custom RecyclerViewAdapter
.
class TestAdapter(var isSelectingEnabled: Boolean) : RecyclerViewBaseAdapter<TestModel>() {
val selectedList: ArrayList<TestModel>? = null
override fun getLayoutResId(viewType: Int): Int = R.layout.test_list_item
var onItemClick: ((TestModel) -> Unit)? = null
override fun bindData(
holder: SimpleViewHolder<TestModel>,
model: TestModel,
position: Int
) {
val context = holder.itemView.context
val checkBox = holder.itemView.findViewById<MaterialCheckBox>(R.id.checkbox)
holder.itemView.setOnClickListener {
onItemClick?.invoke(model)
}
checkBox.apply {
checkBox.setOnCheckedChangeListener(null)
checkBox.isChecked = model.isSelected
isVisible = isSelectingEnabled
setOnCheckedChangeListener { buttonView, isChecked ->
selectedList?.add(model)
}
}
}
}
In Fragment:
private fun removeListItems() {
if (!testAdapter.isSelectingEnabled) {
testAdapter.removeAllItems(arrayList)
arrayList.clear()
binding.buttonBulkAddRemove.isEnabled = false
} else {
if (arrayList.size > 0) {
testAdapter.selectedList?.forEach {
if (arrayList.contains(it)) {
testAdapter.removeItems(it)
arrayList.remove(it)
}
}
}
}
}
Defined few methods in BaseAdapter
class as:
fun removeItems(model: T): Boolean {
val index = dataList.indexOf(model)
val removed = dataList.remove(model)
if (removed) {
notifyItemRemoved(index)
}
return removed
}
fun removeAllItems(listItems: List<T>) {
dataList.removeAll(listItems)
notifyDataSetChanged()
}
Please guide me if I'm doing anything wrong.
CodePudding user response:
Your selectedList
is null. You should use val selectedList = mutableListOf<TestModel>()
.
Also, you probably want to be removing items from the list when they are unchecked.
In my opinion, however, you should change your strategy. This selectedList
is going to be tricky to keep synced with your UI state, especially after a screen rotation. Instead, you can simply iterate your Adapter's source list and remove the items that are isSelected
. Then notify the Adapter of the change.
I guess that list is in your base adapter class that you haven't shown. This will be kind of complicated using repeated notifyRangeRemoved
calls, or you can use notifyDataSetChanged()
and suffer the ugly refresh of your list. It would be easier if you were using ListAdapter as your base class.
Edit, based on updated question:
Quick and dirty solution: remove selectedItems
from your adapter and all the code interacting with it. Add a function like this to TestAdapter and use it in your Fragment:
fun removeAllCheckedItems() {
dataList.filter { it.isSelected }
.forEach { removeItems(it) }
}
Change your checked change listener to actually update your model items. You need to do this anyway because otherwise they will show the wrong check box state when they scroll off the screen and come back.
setOnCheckedChangeListener { buttonView, isChecked ->
model.isChecked = isChecked
}
However, I recommend using read-only Lists, an immutable model class, and ListAdapter for cleaner, more robust code. But that is a lot more involved to change, and far too much to go over in an answer here. You can read about these various subjects by doing a web search for articles about them.