0

I have a recyclerView that supports drag and drop. When I drag a viewHolder to the end of the list it keeps dragging past the last index. What is the proper way to make it stop dragging when it reaches the end? Right now, when "dropped" it snaps back to the last position in the RecyclerView.

This is with recyclerView's height="match_parent"

enter image description here

This is with recyclerView's height="wrap_content"
enter image description here

After reading this post, I tried preventing this behavior in the onChildDraw method of the ItemTouchHelper. The 3 things I tried to stop the dragging at the last index all work, but the swapping animations aren't fluid at all. What is the proper way to handle this? Also, is this ItemTouchHelper/recyclerView's standard behavior (to not stop dragging at beginning/end of the list)? I find it hard to believe that the default behavior allows this and I'm wondering if it's my implementation that's causing this.

@Override
public void onChildDraw(@NonNull Canvas canvas,
                        @NonNull RecyclerView recyclerView,
                        @NonNull RecyclerView.ViewHolder viewHolder,
                        float dX, float dY, int actionState, boolean isCurrentlyActive) {

  if(actionState == ItemTouchHelper.ACTION_STATE_DRAG) {

    // FIRST THING I TRIED
    // This works but slows the swapping animations down. When fast dragging an item down to the
    // bottom it's like it hit a brick wall and the viewHolder bounces upward a little before settling in
    // the last position
    if(viewHolder.getAdapterPosition() == recyclerLastIndex || viewHolder.getAdapterPosition() == 0) {
            return;
    }

    // SECOND THING I TRIED
    // This also works but I lose the fluid swapping animations while dragging. The swap is very abrupt.
    recyclerView.getLocationOnScreen(posXY);  // method uses a 2 element array (posXY) to store X and Y coordinates
    int yPosOfRecycler = posXY[1]; // Y coordinate is stored in the second position
    viewHolder.itemView.getLocationOnScreen(posXY);
    int yPosOfViewHolder = posXY[1];
    if(yPosOfViewHolder > yPosOfRecycler) {
      return;
    }

    // THIRD THING I TRIED
    // Works but swapping animations are also lost 
    if(!recyclerView.canScrollVertically(1)) {
            return;
    }

    // If I comment out the code in the 3 approaches above, the swapping animations are beautifully
    // smooth, but will allow dragging past the boundaries of the recyclerView  
    super.onChildDraw(canvas, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
  }
}
gig6
  • 307
  • 5
  • 16
  • How about the code which produces the issue instead of showing some failed workaround? – Martin Zeitler Jan 12 '21 at 01:05
  • I think this is normal behavior. – Sam Chen Jan 12 '21 at 03:40
  • @MartinZeitler I have determined that the call to super.onChildDraw is what is allowing items to be dragged past the recyclerView boundary. However, if I don't call it, dragging items is not fluid at all. It's not a very good user experience. – gig6 Jan 12 '21 at 17:48
  • @SamChen When I don't call super.onChildDraw, dragging stays within the boundaries of the first and last place in the recyclerView (which is what I would expect) but I lose the fluid dragging animation. It's only when I call super.onChildDraw does this dragging out of bounds occur. Is there a workaround that you know of for this? – gig6 Jan 13 '21 at 23:36

0 Answers0