How to show single item selected in recyclerview using kotlin - android

How can we mark single item is selected in Recyclerview using kotlin. When I select an item and after that click on other item then previously selected item should be dis-selected.Here is my adapter class in kotlin:..
class ListAdapter(var context: Context, var list: ArrayList<ListModel>) : RecyclerView.Adapter<ListAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MyViewHolder {
val v = LayoutInflater.from(parent?.context).inflate(R.layout.list_item, parent, false)
return MyViewHolder(v)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: MyViewHolder?, position: Int) {
holder?.bindItems(list[position])
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view){
fun bindItems(items: ListModel) {
itemView.txt_que.text = items.que
itemView.txt_ans.text = items.ans
itemView.txt_sr_no.text = items.srNo
}
}`

Here dataItem is Model Class and please take one extra Boolean variable isSelected in model class (default value is false) and true when select item then true this variable on selected position,
below are example :
class AllModuleListAdapter(
var context: Context?,
private var moduleList: ArrayList<DataItem?>?,
private var mCallback: DeviceClickListener
) :
RecyclerView.Adapter<AllModuleListAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val context = parent.context
val itemView = LayoutInflater.from(context).inflate(R.layout.item_modules, parent, false)
return MyViewHolder(itemView)
}
override fun getItemCount(): Int {
return moduleList?.size ?: 0
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(moduleList?.get(position))
if (moduleList?.get(position) is DataItem) {
val dataItem = moduleList?.get(position) as DataItem
if (dataItem.isSelected) {
context?.let { ContextCompat.getColor(it, R.color.colorOrange) }
?.let { holder.itemView.setBackgroundColor(it) }
} else {
context?.let { ContextCompat.getColor(it, R.color.white) }
?.let { holder.itemView.setBackgroundColor(it) }
}
}
}
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
init {
itemView.constraint_main.setOnClickListener {
val list = moduleList as List<DataItem>
for (item in list.indices) {
list[item].isSelected = false
}
list[adapterPosition].isSelected = true
mCallback.onDeviceClick(adapterPosition)
notifyDataSetChanged()
context?.let { it1 -> ContextCompat.getColor(it1, R.color.colorOrange) }?.let { it2 ->
itemView.constraint_main?.setBackgroundColor(it2)
}
}
}
fun bind(module: DataItem?) {
itemView.txtModuleName?.text = module?.id.toString()
itemView.txtSignal?.text = module?.room
}
}
}

if (mPosition == position)
{
//set selected here
} else
{
//set unselected here
}
holder.parentView.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
mPosition = position;
notifyDataSetChanged();
}
});
Write above code in onBindViewholder and declare mPosition as global int variable in adapter class

Try with this:- take one variable in your ListModel class as
var selected:boolean = false
then while setting the listModel items set this value as false as
for(int i=0;i<listModel.size;i++){
listModel.get(i).selected = false
}//this is for setting all values false
when you select any item from list call this method and then set selected = true for selected position and simply refresh the adapter list.
in your adapter check for this selected value and accordingly set the check box value inside your bindItems method
itemView.checkBox.selected = items.selected//this will set your checkbox selected value

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

Notifying an item changed inside a nested adapter

I have one ParentAdapter that has multiple view holders and each view holder has its own RecyclerView and an adapter.
I am facing a problem when I need to notify an item of a child adapter is changed. I passed the position of the changed child view holder to the parent and I can use notifyItemChanged(position) but the whole child adapter is recreated.
What I need is to be able to notify a child item and keep the state of the child recyclerview as it is.
Here's the code of the Parent Adapter:
class ParentAdapter(): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private lateinit var context: Context
private var items = listOf<ParentItem>()
companion object {
const val CHILD_ONE = 1
const val CHILD_TWO = 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
context = parent.context
val layoutInflater = LayoutInflater.from(context)
return when(viewType) {
CHILD_ONE -> {
ChildOneViewHolder(layoutInflater.inflate(R.layout.child_one, parent, false))
}
CHILD_TWO -> {
ChildTwoViewHolder(layoutInflater.inflate(R.layout.child_two, parent, false))
}
else -> {
BlankItemViewHolder(layoutInflater.inflate(R.layout.fragment_blank, parent, false))
}
}
}
fun update(items: List<Section>) {
this.items = items
notifyDataSetChanged()
}
override fun getItemViewType(position: Int): Int {
val item = items[position]
return when(item.type) {
1 -> CHILD_ONE
2 -> CHILD_TWO
else -> -1
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder.itemViewType) {
CHILD_ONE -> {
val section = items[position]
val childOneAdapter = ChildOneAdapter(this)
if(!section.items.isNullOrEmpty()) {
holder.rvChildOne.apply {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
adapter = childOneAdapter
isNestedScrollingEnabled = true
}
childOneAdapter.update(section.items)
}
}
CHILD_TWO -> {
val section = items[position]
val childTwoAdapter = ChildTwoAdapter(this)
if(!section.items.isNullOrEmpty()) {
holder.rvChildTwo.apply {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
adapter = childTwoAdapter
isNestedScrollingEnabled = true
}
childTwoAdapter.update(section.items)
}
}
else ->
initBlankSection(holder as BlankItemViewHolder, position)
}
}
private fun initBlankSection(holder: BlankItemViewHolder, position: Int) {
}
private class ChildOneViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val rvChildOne: RecyclerView = itemView.findViewById(R.id.rv_child_one)
}
private class ChildTwoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val rvChildTwo: RecyclerView = itemView.findViewById(R.id.rv_child_two)
}
private class BlankItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {}
override fun getItemCount(): Int = items.size
}

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)
}
}
}

Why RecyclerView Adapter updating the instance of list of object that was passed to it

I am having an issue with recyclerview.adapter what i am doing is
Passing a list of objects to a dialog where dialog have a recyclerview and two buttons.
1. Cancel and 2. Done
If user selects items from recyclerview that will be passed to fragment.
Now assume if user have 2 items already selected, and opens dialog for more and selected some items but now user wants to cancel the selection and go back(without unselecting the ites) to fragment with old data but currently it is updating the list of object of fragment.
Here is the code of dialog.
fun showChooserDialog(
baseActivity: AppCompatActivity,
typeCode: Int,
dataList: ArrayList<PrefsStateModel>
) {
var alertDialog: AlertDialog? = null
val dialogBuilder =
AlertDialog.Builder(baseActivity, R.style.CustomDialog)
dialogBuilder.setCancelable(true)
val inflater = LayoutInflater.from(baseActivity)
val dialogView: View = inflater.inflate(R.layout.view_select_prefs, null)
dialogBuilder.setView(dialogView)
val btnCancel = dialogView.findViewById<MaterialButton>(R.id.btnCancel)
val btnDone = dialogView.findViewById<MaterialButton>(R.id.btnDone)
val recyclerView = dialogView.findViewById<RecyclerView>(R.id.listViewPrefs)
recyclerView.setHasFixedSize(true)
val layoutManager = LinearLayoutManager(baseActivity)
recyclerView.layoutManager = layoutManager
val adapter =
SelectPrefAdapter(
baseActivity,
dataList
)
recyclerView.adapter = adapter
btnCancel.setOnClickListener {
preferenceView.onUserNotSelected()
alertDialog?.dismiss()
}
btnDone.setOnClickListener {
val data = adapter.getList()
preferenceView.onUserSelectedPrefDone(data, typeCode)
alertDialog?.dismiss()
}
alertDialog = dialogBuilder.create()
alertDialog.window?.setLayout(600, 400)
alertDialog.show()
}
What i wants to do when user clicks on cancel button even he selected the more items from recyclerview, then the fragment's recyclerview should not update the items. it must be showing the old items. but currently it is updating the items even i am not passing when clicking on cancel button.
Here is adapter's code.
class SelectPrefAdapter(var context: Context, var dataList: ArrayList<PrefsStateModel>) :
RecyclerView.Adapter<SelectPrefAdapter.UserViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, p1: Int) =
UserViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.view_pref_adapter, parent, false)
)
override fun getItemCount() = dataList.size
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
var prefsState = dataList[position]
holder.lable.text = prefsState.name
if (prefsState.isSelected) {
holder.lable.setTextColor(context.resources.getColor(R.color.colorPrimary))
holder.icon.visibility = View.VISIBLE
} else {
holder.lable.setTextColor(context.resources.getColor(R.color.colorGreyShade2))
holder.icon.visibility = View.INVISIBLE
}
holder.lable.setOnClickListener {
if (prefsState.isSelected) {
prefsState.isSelected = false
holder.lable.setTextColor(context.resources.getColor(R.color.colorPrimary))
holder.icon.visibility = View.VISIBLE
} else {
prefsState.isSelected = true
holder.lable.setTextColor(context.resources.getColor(R.color.colorGreyShade2))
holder.icon.visibility = View.INVISIBLE
}
notifyDataSetChanged()
}
}
class UserViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val icon = view.imageViewIcon
val lable = view.textviewPrefName
}
fun getList(): ArrayList<PrefsStateModel> {
return dataList
}
}
This is main adapter code from where i pass the data to dialog's recyclerview adapter.
class ProfilePrefAdapter(
var context: Context,
var dataListPref: ArrayList<PrefsStateModel>,
var onPrefSelection: OnPrefSelection
) :
RecyclerView.Adapter<ProfilePrefAdapter.PrefViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, p1: Int) = PrefViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.view_pref, parent, false)
)
override fun getItemCount() = dataListPref.size
override fun getItemViewType(position: Int): Int {
return super.getItemViewType(position)
}
override fun onBindViewHolder(holder: PrefViewHolder, position: Int) {
val prefs = dataListPref[position]
holder.chipView.text = prefs.name
if (prefs.isSelected) {
holder.chipView.setBackgroundResource(R.drawable.rounded_border_selected)
holder.chipView.setTextColor(context.resources.getColor(R.color.colorWhite))
} else {
holder.chipView.setBackgroundResource(R.drawable.rounded_border_unselected)
holder.chipView.setTextColor(context.resources.getColor(R.color.colorGreyShade1))
}
if (position == dataListPref.size - 1) {
onPrefSelection.onPrefSelection(getSelected())
}
holder.chipView.setOnClickListener {
if (prefs.isSelected) {
prefs.isSelected = false
holder.chipView.setBackgroundResource(R.drawable.rounded_border_unselected)
holder.chipView.setTextColor(context.resources.getColor(R.color.colorGreyShade1))
} else {
prefs.isSelected = true
holder.chipView.setBackgroundResource(R.drawable.rounded_border_selected)
holder.chipView.setTextColor(context.resources.getColor(R.color.colorWhite))
}
notifyDataSetChanged()
onPrefSelection.onPrefSelection(getSelected())
}
}
class PrefViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val chipView = view.textViewPref
}
fun setList(data: ArrayList<PrefsStateModel>) {
clearData()
dataListPref.addAll(data)
notifyDataSetChanged()
}
private fun clearData() {
dataListPref.clear()
}
fun getData(): List<PrefsStateModel> {
return dataListPref.toMutableList()
}
private fun getSelected(): Int {
var count = 0
for (data in dataListPref) {
if (data.isSelected) {
count++
}
}
return count
}
}
This is where i am getting data and passing to dialog.
private fun showDialog(type: Int) {
var dataToPasses: ArrayList<PrefsStateModel>? = ArrayList()
when (type) {
1 -> {
dataToPasses?.clear()
dataToPasses?.addAll(adapterGener!!.getData())
}
2 -> {
dataToPasses?.clear()
dataToPasses?.addAll(adapterContent!!.getData())
}
3 -> {
dataToPasses?.clear()
dataToPasses?.addAll(adapterLanuage!!.getData())
}
}
utils.showLog(TAG, "data to be sent to dialog $dataToPasses and $generPrefList")
preferencePresenter.showChooserDialog(baseActivity, type, dataToPasses!!)
}
It's happing because your fragment and recyclreview are working on the same object list its called shallow copy. time both has the latest copies of data. to solve this problem you need to create deep copy and pass that to the adapter.
Example
ArrayList<PrefsStateModel> newList = new ArrayList<PrefsStateModel>();
for(PrefsStateModel p : oldList) {
newList.add(p.clone());
}
public class PrefsStateModel{
String s;
Date d;
...
public PrefsStateModel clone(){
PrefsStateModel p = new PrefsStateModel();
p.s = this.s.clone();
p.d = this.d.clone();
...
return p;
}
}

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