Single item selection can be maintained in RecyclerView by
- Two variables to be kept updated when an item is selected
- The first variable maintains the currently selected position
- The second variable maintains the last selected position
- Two different background drawable for the selected and unselected
items
- Two methods in ViewHolder Class to change the background of items
Background drawable
For the item selected in my example:
Drawable name: bg_capsule_selected
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="300dp" />
<stroke
android:width="1dp"
android:color="@color/white" />
<solid android:color="@color/colorOffGreen" />
</shape>
For the item unselected
Drawable name: bg_capsule_unselected
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="300dp" />
<stroke
android:width="1dp"
android:color="#11B8B7BA" />
<solid android:color="#F3F3F4" />
</shape>
Variables
Two variables to be initialized in your Adapter Class
var selectedItemPos = -1
var lastItemSelectedPos = -1
Separate methods in the ViewHolder Class for changing the background of the items when selected and unselected
fun defaultBg() {
binding.tvCurrencyName.background = context.getDrawable(R.drawable.bg_capsule_unselected)
}
fun selectedBg() {
binding.tvCurrencyName.background = context.getDrawable(R.drawable.bg_capsule_selected)
}
Logic
The logic is to update the variables and calling the notifyItemChange(position)
which would then call the method onBindViewHolder(holder: ViewHolder, position: Int)
for this to happen we have to initialize the click listener for each of the itemViews
and update the variables accordingly with the adapter position and call notifyItemChange()
method with passing the item position to change
init {
itemView.setOnClickListener {
selectedItemPos = adapterPosition
if(lastItemSelectedPos == -1)
lastItemSelectedPos = selectedItemPos
else {
notifyItemChanged(lastItemSelectedPos)
lastItemSelectedPos = selectedItemPos
}
notifyItemChanged(selectedItemPos)
onItemClick?.invoke(itemDate) // here you can keep the callback
}
}
this code is written inside the ViewHolder Class as an init block Since we have set click listeners for every itemView
and then when we call notifyItemChange()
method would call onBindViewHolder()
method and in this method, we would check for the position and change their background with the help of two methods written inside ViewHolder Class like this
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if(position == selectedItemPos)
holder.selectedBg()
else
holder.defaultBg()
holder.bindItems(adapterList[position])
}