As far as I can tell, View
s only receive DragEvent
s if they had implemented onDragEvent()
or had set an OnDragListener
before startDrag()
(or startDragAndDrop()
for API 24 ) is called. They will then continue to receive additional drag events if they return true
for DragEvent.ACTION_DRAG_STARTED
.
However, I am looking for a way to receive DragEvent
s after a drag operation had already started, for View
s that got added to the layout during the drag operation.
To illustrate why, my situation is roughly the following:
I have a ViewPager2
with ListView
fragments whose list items can be dragged. If I drag an item over another item, I "enter" that item and a new ListView
fragment is shown with new child items. This works fine.
However, since these new child items didn't exists at the time of starting the drag operation, they don't receive DragEvent
s when I continue to drag the item over those new items.
So, basically, I want to be able to enter multiple levels deep in one continuous drag operation.
Is it possible to have newly added View
s receive DragEvent
s for an ongoing drag operation?
CodePudding user response:
Okay, I've managed to solve it by re-dispatching the original DragEvent
(the one with action DragEvent.ACTION_DRAG_STARTED
) to my main component, which is an instance of ViewGroup
.
On inspecting the source code for ViewGroup.dispatchDragEvent()
I found that ViewGroup
has a member variable called mChildrenInterestedInDrag
that gets filled with children interested in drag events, when DragEvent.ACTION_DRAG_STARTED
is received.
So when I called ViewGroup.dispatchDragEvent()
with the original DragEvent
, after I entered an item in the list to view its child items, those new ListView
child items were now responding to additional DragEvent
s.
I'm a bit worried that this approach might yield unexpected side effects. If I come across such effects upon further testing, I'll update this answer. But for now it will do.
If somebody knows that this indeed might yield unexpected side effects and/or has a better solution I'd love to hear them.
Addendum:
Upon storing the original DragEvent
for re-dispatching, I had to "clone" the event, because, while it worked properly in an API 19 emulator, on an API 19 phone the original DragEvent
's action were continuously altered during dragging, so its action wouldn't reflect DragEvent.ACTION_DRAG_STARTED
anymore and re-dispatching didn't have the desired effect of registering newly added View
s as interested in the ongoing drag operation.
Since DragEvent
s cannot be cloned or constructed, I had to "clone" it with the help of a Parcel
:
void storeStartEvent(DragEvent startEvent) {
Parcel parcel = Parcel.obtain();
startEvent.writeToParcel(parcel, 0);
// important to "rewind" the Parcel first
parcel.setDataPosition(0);
this.startEvent = DragEvent.CREATOR.createFromParcel(parcel);
}
Other than that, I didn't experience any noticeable problems yet, so it may have just solved my issue nicely.