I am using RecyclerView
in my app, it has itemViewCache
of 20 items because max possible size of my list would be 20. It is "Single Item Selection List". Now When the list loads, the first cell becomes highlighted as default selected position. If i click the cell at different position, the view at that position becomes selected & highlighted, simultaneously previously selected view becomes white ie unselected.
Above works fine as I use adapter.notifyDataSetChanged(position, payLoad)
method to update data in the list. But when the cell at currently selected position is scrolled out of the screen and I try to select new position, however the new cell grabs the highlighting and becomes selected, it does not makes previously selected cell white. For the cell at scrolled out position, system dont even call the notifyDataSetChanged(positioin, payLoad)
method to make ui in it. Any help would be greatly appreciated as I work a lot with RecyclerViews
.
Here is the code of my adapter :
class EventsCalendarAdapter(var eventSectionedFrag: EventSectionedFrag, var arrayList: ArrayList<String>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.adapter_calendar_months, parent, false)
return CalendarHolder(view)
}
override fun getItemCount() = arrayList.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: MutableList<Any>) {
if (payloads.isNotEmpty()) {
var bundle = payloads[0] as Bundle
var isSelected: Boolean? = bundle.getBoolean("selected")
var setCurrentMonthSelected: Boolean? = bundle.getBoolean("setMonth")
with(holder) {
if (isSelected != null) {
val tvMonth = itemView.findViewById<TextView>(R.id.tv_month)
tvMonth.apply {
setTextColor(ContextCompat.getColor(eventSectionedFrag.activity!!, if (isSelected) R.color.white else R.color.better_than_black))
background.setColorFilter(ContextCompat.getColor(eventSectionedFrag.activity!!, if (isSelected) android.R.color.holo_red_light else R.color.white), PorterDuff.Mode.SRC)
}
}
if (setCurrentMonthSelected != null) {
val view = itemView.findViewById<View>(R.id.view_current)
view.visibility = if (setCurrentMonthSelected) {
View.VISIBLE
} else {
View.INVISIBLE
}
}
}
} else {
super.onBindViewHolder(holder, position, payloads)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val myHolder = holder as CalendarHolder
myHolder.bindItems(eventSectionedFrag = eventSectionedFrag, month = arrayList[position], position = position)
}
class CalendarHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(eventSectionedFrag: EventSectionedFrag, month: String, position: Int) {
val tvMonth = itemView.findViewById<TextView>(R.id.tv_month)
val cardMonth = itemView.findViewById<ConstraintLayout>(R.id.card_month)
val view = itemView.findViewById<View>(R.id.view_current)
view.visibility = View.INVISIBLE
val callbacks = eventSectionedFrag as CalendarCallbacks
tvMonth.text = month
view.apply {
visibility = if (callbacks.getCurrentMonthPosition() == position) {
View.VISIBLE
} else {
View.INVISIBLE
}
}
cardMonth.setOnClickListener {
callbacks.onMonthSelected(adapterPosition, tvMonth)
}
}
}
fun addMonths(arrayList: ArrayList<String>) {
this.arrayList.clear()
this.arrayList.addAll(arrayList)
notifyDataSetChanged()
}
interface CalendarCallbacks {
fun onMonthSelected(position: Int, currentSelectedView: TextView)
fun getCurrentMonthPosition(): Int
}
}
and here is how I am invoking the changes from my activity,
override fun notifyCalendar(isCurrentYearSelected: Boolean, position: Int) {
var bundle = Bundle()
bundle.putBoolean("setMonth", isCurrentYearSelected)
calendarAdapter.notifyItemChanged(position, bundle)
}
From the RecyclerView.Adapter#notifyItemChanged(int position, java.lang.Object payload)
docs:
Adapter should not assume that the payload will always be passed to onBindViewHolder(), e.g. when the view is not attached, the payload will be simply dropped.
So when the cell at currently selected position is scrolled out of the screen, nothing will change because the old selected view is not exist.
You can modify your arrayList
to store the selected status in it, or add a method to CalendarCallbacks
which can fetch the current selected position, but you must take care of changing the selected position when needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With