Search code examples
androiddrag-and-dropandroid-recyclerviewgridlayoutmanageritemtouchhelper

Android - RecyclerView drag using ItemTouchHelper.Callback


I'm currently working on an small Android module and I'm facing a problem which maybe someone can solve. I need to create a calendar and allow the user to select a date range by 1) clicking on a start date (this will create a 2 days range by default) and then 2) touching one range border and dragging it to increase or decrease that range.

Currently I've created all the calendar days cells using a RecyclerView with a GridLayoutManager which has a lot of rows (all the weeks) with 7 items per row (the days). Then I've used the RecyclerView ItemTouchHelper (https://developer.android.com/reference/android/support/v7/widget/helper/ItemTouchHelper.html) and ItemTouchHelper.Callback (https://developer.android.com/reference/android/support/v7/widget/helper/ItemTouchHelper.Callback.html) to complete the drag&drop functionality. My approach was to use the drag&drop detection provided by those helpers (take a look at https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf#.ib8r012gc) modifying it to avoid moving one item and only detecting the touch+drag+drop gesture I wanted. I've correctly completed the functionality by removing the default drag animation (overriding ItemTouchHelper onDraw/onDrawOver) and using the ItemTouchHelper.Callback callbacks to manage the drag movement (without swapping the adapter items, because I need them always at the same position). All works fine but I'm now facing a problem because the drag detection is not working as expected. I'll try to explain it: if I start the drag movement in the center of a given cell, and I move to the cell to its left, the drag movement isn't triggered until I've reached the center (the same position at where I've started the drag movement) of the left cell. This is a problem because I need to detect a drag as soon as I reach another cell (if the finger is inside the new cell bounds, the drag should be triggered). Another example is: if I start the drag movement in the leftmost side of a cell, the drag won't be triggered until I reach the leftmost side of another cell.

Now I'm trying to play a bit with the ItemTouchHelper.Callback.chooseDropTarget method to manually select the drop target as soon as the fingers enters a new cell but I'm not able to get it work. I think (but I cannot ensure it) that is something strange with the received x,y coordinates.

I know that some code example would be very helpful but I cannot paste it because it belongs to a private and protected repository :(

Any help that anyone could provide to me will be really appreciated. And, of course, I'll try to be pending of this topic to provide all the info I can. I will also take into account new different approaches and suggestions to get the "touch+move+up" movement which I need to move ranges borders :)

Many thanks in advance to all the Stack Overflow community!


Solution

  • After some more research, I found the solution to my problem. I'll post it so if someone faces the same issue, he can find some help here :)

    My problem was that I was using the curX and curY parameters returned by ItemTouchHelper.Callback.chooseDropTarget (https://developer.android.com/reference/android/support/v7/widget/helper/ItemTouchHelper.Callback.html#chooseDropTarget(android.support.v7.widget.RecyclerView.ViewHolder,%20java.util.List%3Candroid.support.v7.widget.RecyclerView.ViewHolder%3E,%20int,%20int)) as if they were the current finger coordinates while dragging, but they are the coordinates of the top leftmost coordinate of the dragged view after applying any translation. Now I feel a bit stupid. I should have read the documentation better :|

    As I didn't need that top leftmost coordinate but the finger position, my solution was to use a touch listener attached to the source view so I could detect the initial touch x,y coordinates (relative to that view) using the touchSrcX = MotionEvent.getX() and touchSrcY = MotionEvent.getY() methods and then I applied a point translation before selecting a target in the chooseDropTarget callback. I mean, something like: curX += touchSrcX curY += touchSrcY

    If someone needs more details or a better explanation, please, contact me and I'll be pleased to help! :)