Tobi
Tobi

Reputation: 100

RecyclerView gets not notified about visual changes when using the recyclerview-selection library

I have implemented the recyclerview-selection library successfully. Now I am trying to make a "select all items" button with the method SelectionTracker.setItemsSelected(keys: Iterable<K>, selected: boolean). So far so good. My problem is now that some of the items which are out of sight don´t get visually checked. But this just happens if I scrolled down to the list´s end bevor pressing the button. Under the hood all items get checked which I can see on the app bar´s text.

Example: I scroll to the end of the list and back up and press then the "select all items" button. As you can see in the picture there a some items that are visually not checked.

'n' and 'o' are not chekced

Similar things happen if I press the back button to remove the checked state of all items.


Now my question: Is there a bug in the recyclerview libraries which causes this weird gui behaviour or am I doing something wrong? I am using the following version: recyclerview-selection:1.1.0-rc03


EDIT:

Here the bind method of my RecyclerView.ViewHolder class:

fun bind(event: Event, selected: Boolean) {
    val imgSize = if (selected) SELECTION_IMG_EXTENDED_SIZE else SELECTION_IMG_REDUCED_SIZE
    animateResize(imgSize, ...)
}

Upvotes: 2

Views: 392

Answers (1)

Tobi
Tobi

Reputation: 100

According to the documentation I solved the problem by overriding the following method:

RecyclerView.Adapter:

override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
      val isSelected = selectionTracker.isSelected(holder.itemId)
      holder.setItemSelected(isSelected)
}

I don't know if this is the recommended way to solve the problem but maybe it will help someone. Let me know if you have any more tips or information for me!


EDIT:

Here the full code:

class EventAdapterAll(private val context: Context) : ListAdapter<Event, EventAdapterAll.EventViewHolder>(EventAdapterDiffCallback()) {

    private val commonListAdapter = CommonListAdapter()

    init {
        setHasStableIds(true)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventViewHolder {
        val binding = LayoutEventItemAllBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return EventViewHolder(binding)
    }

   override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
        val currentItem = getItem(position)
        commonListAdapter.selectionTracker?.let {
           holder.bind(currentItem, it.isSelected(getItemId(position)))
        }
    }

    override fun onViewAttachedToWindow(holder: EventViewHolder) {
        val isSelected = commonListAdapter.selectionTracker?.isSelected(holder.itemId)
        if (isSelected != null) {
            holder.setItemSelected(isSelected)
        }
    }

    //...

    inner class EventViewHolder(private val binding: LayoutEventItemAllBinding) : RecyclerView.ViewHolder(binding.root) {

        fun bind(event: Event, selected: Boolean) = with(binding) {
            setItemSelected(selected)
            //...
        }

        fun setItemSelected(selected: Boolean) {
            val imgSize = if (selected) SELECTION_IMG_EXTENDED_SIZE else SELECTION_IMG_REDUCED_SIZE
            commonListAdapter.animateResize(binding.imgEventSelection, imgSize, context)
        }
    }
}

When scrolling down/up and the list items become visible, onViewAttachedToWindow ensures that the selection status in the list gets updated.

Upvotes: 1

Related Questions