4

I need to execute something when the user drops an item. The ItemTouchHelper seems to only have calls for onMove and onMoved which happen regardless of whether the user is actually done moving the item. How do I know when the user has finished moving an item? Ie, they have released their finger and dropped the item back into the recyclerView?

Zoe
  • 27,060
  • 21
  • 118
  • 148
Ben Mora
  • 279
  • 3
  • 16

3 Answers3

4

You can override onSelectedChanged() callback of the implementation of ItemTouchHelper.Callback class, and check actionState value with a switch case that can be one of (ACTION_STATE_DRAG, ACTION_STATE_SWIPE, & ACTION_STATE_IDLE).

ACTION_STATE_IDLE is what you're looking for, it will be triggered when the swipe/drag actions are over and the user left their finger off the screen

You can use a boolean to figure out whether it's swipe or drag as below.

private ItemTouchHelper createHelperCallback() {
    return new ItemTouchHelper(new ItemTouchHelper.Callback() {

        boolean isSwiped = false;

        @Override
        public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            return 0;
        }

        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        }

        @Override
        public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {

            switch (actionState) {

                case ItemTouchHelper.ACTION_STATE_DRAG:
                    // the user is dragging an item and didn't lift their finger off yet
                   isSwiped = false;
                   break;

                case ItemTouchHelper.ACTION_STATE_SWIPE:
                    // the user is swiping an item and didn't lift their finger off yet
                    isSwiped = true;
                    break;

                case ItemTouchHelper.ACTION_STATE_IDLE:
                    // the user just dropped the item (after dragging it), and lift their finger off.

                    if (isSwiped) // The user used onSwiped()
                        Toast.makeText(MainActivity.this, "Swiping is over", Toast.LENGTH_SHORT).show();
                        
                    else // The user used onMove()
                        Toast.makeText(MainActivity.this, "Dragging & Dropping are over", Toast.LENGTH_SHORT).show();
                    isSwiped = false;
                
            }
        }

    });
}

Then use it on your RecyclerView

createHelperCallback().attachToRecyclerView(recyclerView);

Preview

Zain
  • 37,492
  • 7
  • 60
  • 84
  • Turns out onClear() was what I needed to make it work, but this answer was also very helpful to me, as I was also trying to understand how to make use of those action states. Thanks! – Ben Mora Jan 01 '21 at 16:20
  • 1
    A few things about this answer. Because you don't update the data in `onMove` the other items won't animate out of the way to make room for the dragged item (you can even see this in the vid). Also this answer doesn't track _which item_ actually moved and to where. You'll need to do that in `onMove`. Also you want to reset the `isSwiped/isMoved` state after the `Toast` to safeguard against multiple ACTION_STATE_IDLE calls. Lastly `isSwiped` doesn't need to be a boolean array, just boolean – tir38 Jan 14 '22 at 01:42
3

Easy. Just override onClearView():

@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {    //called when you dropped the item
    super.clearView(recyclerView, viewHolder);

    Toast.makeText(recyclerView.getContext(), "Item dropped on position: " + viewHolder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
Sam Chen
  • 7,597
  • 2
  • 40
  • 73
-1

You can also override getAnimationDuration(), it calls before onSelectedChanged() (just when the user's finger is up) but you can't access viewHolder in this function.

amir_a14
  • 1,478
  • 10
  • 15
  • That seems like an implementation detail that may change without notice in future versions of RV library. – tir38 Jan 14 '22 at 01:44