I implemented a View.OnDragListener
for a simple drag and drop feature, and added additional support for scrolling the parent view while dragging the target. This works fine release the drag at a valid target view (i.e. if onDragEvent
returns false
for DragEvent.ACTION_DROP
). For example here I start dragging folder L, scroll up and drop it to inside folder A, and the animation is working correctly:
This also works fine if I don't scroll while dragging and nothing handles the drop (i.e. if onDragEvent
returns true
for DragEvent.ACTION_DROP
and the position of the dragged view hasn't changed since starting the drag). For example here I start dragging folder L, drag it up to blank space which isn't a valid drop target, and release. The animation moves it back down to where L's original position, looking good.
But as soon as I scroll the parent view while dragging and nothing handles the drop, the animation becomes completely wrong because Android apparently ignores the fact that the view is now sitting at different coordinates than before. It just sets the coordinates at the point of calling startDragAndDrop
and never updates them. For example here I start dragging folder L, scroll up, drag it to blank space which isn't a valid drop target, and release. The animation moves it up because that's where L's original location was relative to the screen, not the scrolling content:
What I need is for L to move down to where it is at the end, not at the start. How can I achieve this? I know the final coordinates, but I don't know how to fix the animation accordingly. I haven't even found any Android SDK code where this release animation is handled (Google seems to handle this magically via SurfaceSession
and a system-private IWindowSession.aidl
).
The code I use for the drag and drop is very simple, it's just this:
val shadow = View.DragShadowBuilder(v)
@Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
v.startDrag(null, shadow, item, 0)
else
v.startDragAndDrop(null, shadow, item, 0)
The code to make it support scrolling is a bit more complicated, something like the solutions to this question: Make a scrollView autoscroll with drag and drop in Android. But that part isn't essential to reproduce it. You basically just need a ScrollView
or RecyclerView
and scroll it programmatically or manually after starting the drag. Nothing fancy.
Please note that I'm showing examples which might lead to the assumption that ItemTouchHelper would solve my problem. In normal situations ItemTouchHelper would be the go-to solution, but in fact, I'm actually using the drag and drop to move views between RecyclerViews (and across fragments), which is not supported by ItemTouchHelper, so it's not applicable in this case.
from startDragAndDrop ignores if dragged view changes its position - How to change where it should return after a drag and drop operation wasn't handled?
No comments:
Post a Comment