Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android limit item dragging in a range itemtouchhelper

I have show a list of Items with RecyclerView and I have items of different types (headers and items), like the following

Header 1
Item 1
Item 2
Header 2
Item 3
Item 4 
Item 5
Item 6
Header 3
Item 7
....

I would like to limit swapping the position of Items inside their section Headers. So for example, Item 4 can be swapped with Item 3, Item 5 and Item 6 but not go outside it's section boundaries. I'm using ItemTouchHelper to implement the swap on drag mechanism as suggested here https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf and https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd I overloaded the canDropOver method which helps if you want to swap for example Item 4 and Header 2 but not in preventing me in dragging the Item till Header 1. Any suggestions?

like image 506
AndrewBloom Avatar asked Sep 03 '25 09:09

AndrewBloom


1 Answers

Once you've got canDropOver set, the last piece of the puzzle is to override onChildDraw and clamp the dY value (assuming a vertical list -- clamp the dX value if using a horizontal list) whenever a ViewHolder is being dragged toward an adjacent ViewHolder it can't drop over.

For example:

    override fun onChildDraw(
        c: Canvas,
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        dX: Float,
        dY: Float,
        actionState: Int,
        isCurrentlyActive: Boolean
    ) {
        val previousViewHolder = recyclerView.findViewHolderForAdapterPosition(viewHolder.bindingAdapterPosition - 1)
        val nextViewHolder = recyclerView.findViewHolderForAdapterPosition(viewHolder.bindingAdapterPosition + 1)
        val isDraggingUpward = dY < 0
        val isDraggingDownward = dY > 0

        val isDraggingIntoUndraggableArea =
            (isDraggingUpward && previousViewHolder != null && !canDropOver(recyclerView, viewHolder, previousViewHolder))
            || (isDraggingDownward && nextViewHolder != null && !canDropOver(recyclerView, viewHolder, nextViewHolder))

        val newDy = if (isDraggingIntoUndraggableArea) {
            0f  // Clamp
        } else {
            dY
        }

        super.onChildDraw(c, recyclerView, viewHolder, dX, newDy, actionState, isCurrentlyActive)
    }

I've also got a repository you can refer to which has a full app example: https://github.com/nihk/ClampedItemTouchHelper

like image 66
N1hk Avatar answered Sep 04 '25 23:09

N1hk