mightyWOZ
mightyWOZ

Reputation: 8355

How to unselect all selected items in RecyclerView's SelectionTracker even if some items are scrolled off the screen?

I am using SelectionTracker to implement a multiple selection RecyclerView. the select/unselect feature works as expected if I do it manually (Item is on the screen and I change its state by tapping) but if I try to unselect all items, some of which are off screen, using clearSelection method of selection tracker it only unselects the items which are currently visible on the screen.

This is how I am building the SelectionTracker

tracker = SelectionTracker.Builder<Long>(
            "mySelection",
            recyclerView,
            MyKeyProvider(recyclerView),
            MyItemDetailsLookup(recyclerView),
            StorageStrategy.createLongStorage()
        ).withSelectionPredicate(
            SelectionPredicates.createSelectAnything()
        ).build()
recyclerAdapter.tracker = tracker

Following is bindItem and onBindViewHolder methods of ViewHolder and adapter respectively

fun bindItems(model: Model, isActivated: Boolean) {
    itemView.isActivated = isActivated
    if(itemView.isActivated){
         /* Do something */
    }
    else{
        /* Do something */
    }
}

override fun onBindViewHolder(holder: RecyclerAdapter.ViewHolder, position: Int) {
     val number = displayList[position]
     tracker?.let {
            holder.bindItems(number, it.isSelected(position.toLong()))
     }
}

I call the clear selection method on click of a menu item

override fun onOptionsItemSelected(item: MenuItem?): Boolean {
    if((selectionMode) && (item?.itemId==android.R.id.home)){
        tracker.clearSelection()
    }
    return super.onOptionsItemSelected(item)
}

Edit: This seems to be a bug in the Library, I have encountered the same issue while using the Android Gmail app, Which I think must be using SelectionTracker

Upvotes: 3

Views: 1993

Answers (1)

Balizok
Balizok

Reputation: 1065

I encountered this issue and finally found a solution in this answer.

Turns out this is a library bug. To resolve it, a solution is to override the onViewAttachedToWindow method in your adapter.

According to the documentation, this method is called when a previously unseen view is about to become visible. You can use it to update the state of the item so that it correctly renders your selected state, like this:

override fun onViewAttachedToWindow(holder: LexemeViewHolder) {
    val isSelected = tracker?.isSelected(holder.itemId)
    if(isSelected != null)
        holder.setItemSelected(isSelected)
}

You also need to define the setItemSelected method in your ViewHolder:

fun bindItems(model: Model, isActivated: Boolean) {
    setItemSelected(isActivated)
}

fun setItemSelected(isSelected: Boolean) {
    itemView.isActivated = isActivated
    if (itemView.isActivated){
         /* Do something */
    }
    else {
         /* Do something */
    }
}

While this may not be the most efficient solution due to potential additional processing, it effectively addresses the problem without requiring a full adapter refresh.

Upvotes: 0

Related Questions