Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android RecyclerView SelectionTracker clears selection on touch outside

I'm trying to implement the android library SelectionTracker which allows to select items in a recyclerView.

Everything works fine except that when I click outside of an item (which is in a grid layout), the all selection is cleared.

I actually have found the code which calls the clearSelection(). It's on the line 78 of the class TouchInputHandler. It then calls the line 64 of ItemDetailsLookup which returns false because the touch event didn't occurred on an item.

I was wondering if anyone have found a workaround to prevent this behavior, because I didn't found any option in the documentation.

It's a gridLayout so it is quite "normal" to have space between items and I don't want my users to clear the selection because they have touch the side of an item.

like image 435
Benjamin Ledet Avatar asked Nov 15 '19 15:11

Benjamin Ledet


1 Answers

This is my solution, based on that if we have predefined ItemDetail that will be used as "this is not the view you can select".

First, inside your ItemDetailsLookup instead of returning null you can pass single item with distinguish data that will make sure there is no name/position collision with any other data you can have

class AppItemDetailsLookup(private val rv: RecyclerView) : ItemDetailsLookup<String>() {

    override fun getItemDetails(e: MotionEvent): ItemDetails<String>? {
        val view = rv.findChildViewUnder(e.x, e.y) ?: return EMPTY_ITEM

        return (rv.getChildViewHolder(view) as AppItemViewHolder).getItemDetails()
    }

    object EMPTY_ITEM : ItemDetails<String>() {
        override fun getSelectionKey(): String? = "empty_item_selection_key_that_should_be_unique_somehow_that_is_why_i_made_it_so_long"
        override fun getPosition(): Int = Integer.MAX_VALUE
    }

}

And then when you are creating SelectionTracker with builder, instead of using standard predicate (default is SelectionPredicates.createSelectAnything()) you make your own that will notify that this EMPTY_ITEM cannot be selected

.withSelectionPredicate(object : SelectionTracker.SelectionPredicate<String>() {
    override fun canSelectMultiple(): Boolean = true
    override fun canSetStateForKey(key: String, nextState: Boolean): Boolean =
        key != AppItemDetailsLookup.EMPTY_ITEM.selectionKey

    override fun canSetStateAtPosition(position: Int, nextState: Boolean): Boolean =
        position != AppItemDetailsLookup.EMPTY_ITEM.position
})

I tested it with LinearLayoutManger, the selection was deselecting all items once i clicked outside any of them (my items did not had spacing decoration, but there were so few of them that i was seeing empty under last item)

like image 199
V-master Avatar answered Sep 28 '22 19:09

V-master