Open ShaMan123 opened 4 years ago
Hi guys,
I had this PR in mind for a few months and now found the time, need and stamina to dive into it.
It was hard at first to understand the inner workings of GestureHandlerOrchestrator
but I pulled through.
The more deeper I went, the more I understood what a fine job you guys do.
Both libraries, this and reanimated, make developing in react-native possible, easy and even effortless, yielding great results.
I wanted it to be even more possible, easy and even effortless, hence this PR.
As far as I'm concerned this is ready for android.
It is stable and seems reliable.
The android native example is alive and kicking, you should take a look. It is very convenient to debug with.
I've introduced 2 new gesture handlers:
DragGestureHandler
& DropGestureHandler
, both extend PanGestureHandler
.
Activation logic:
DragGestureHandler
's PanGestureHandler
decides if to activate or not. If it does a drag session begins.DropGestureHandler
s are continuously activated as the event proceeds and cancelled once the pointer exits their bounds.I've decided on a simple mechanism to determine if a drag event can relate with a drop handler. It is passed as types: number | number[]
prop. If both share a type the event is delivered.
Android doesn't fire MotionEvent
during DragEvent
so I've synthesized one and used GestureHandlerOrchestrator
to deliver it normally in order to support simultaneous handlers etc... I think this is a sound approach but might be vulnerable. If issues will rise due to this (e.g. bad MotionEvents) then I suggest adjusting the synthetic MotionEvent
to better impersonate a real one.
Speaking of, I've managed to run a drag handler and a scroll handler simultaneously only on the native example and couldn't get it working in react-native. I hope you guys can suggest the source of this issue, the only thing that I can think of is a root view that needs to listen to FIXEDonDrag
as well as intercepting the event (which sounds wrong) or some internal react-native logic.
I've written the handlers to be compatible with external drag events coming from different apps (both platforms seem to support this) but there's some minor work/testing to be done to finalize it.
Best practice regarding nesting Drag/Drop handlers fora view hierarchy: Drag at top, Drop nested deep.
In the example I've tested a few situations. One of them being using the event data only and handling UI with pan event data. This is possible when passing shadowEnabled=false
. The thing with this is elevation, no problem on the native example (guessing it is caused by ShadowNode
overriding it). This is a caveat for future work, drag shadow works well and is the native approach.
Already I can say this saves tons of boilerplate and logic that mimics drag&drop interactions. I am sure it will resolve a lot of performance issues as well, especially when integrated with reanimated. I have an idea for this too, using a PropsNode
to update a drop zone with the data received from the drag event, all without crossing the bridge once. Sounds exciting, and you can see it opens up new possibilities.
I found a MAJOR bug that was preventing interaction management with native view handlers. cf8e911 fixes the ability to configure interactions with NativeViewGestureHandler based on createHandler#transformIntoHandlerTags.
Check it out - Multi window support!
@osdnk @kmagiera android is ready for reviewing
Thank you for working on this however I need to point out that this PR is very difficult to review at the current state. What could help is to split it into smaller changes (not sure if I understand correcly but seem like there are some unrelated changes here), and or provide some pointers in the PR description as to what changes are being made, in which files and why.
Apart from that I am not sure if I understand the motivation and why PanGestureHandler cannot be used for the use case you are describing?
@kmagiera please refer to the top. I've edited the first comment, hope it gives a better understanding of this PR in terms of motivation, necessity and logic. I've updated the fork so it is even with master.
android is done
Thanks for your work. I regret to say that this code is unreviewable. I hope it's a valuable code but I'm afraid merging over 4k lines in one batch. Can you maybe split your work in a few independent PRs to make it possible to review?
@osdnk What do you suggest? How should I split the code? sounds awkward. I can't think of an effective way of doing it. Are there any other options?
The only thing I can think of is extracting the android native app upgrade (1K of changes)
So there's no way for making it a bit smaller? I'll be even happy with merging smaller chanks of compilable non-breaking code if we'll be able to review it
I'll try something. What about DMNodes? I've tried pinging you there
@ShaMan123 I tried the examples but for some reason can't get it to work. Views are showing but nothing happens when I long press the items on Android. Tried adding the resizeableActivity flag - any other ideas on how to proceed?
Really excited about this possibility since I'm interested in both cross-app functionality and smooth drag-and-drop in lists. I'd be invested in seeing it working on iOS and the web as well. Running a moto g7 play on Android 9 (React Native 0.62.2).
Which example did you try Drag & Drop
or Drag & Drop in FlatList
? Did you try just dragging without long pressing?
In Example/draggable
index.js
is a simple PanGestureHandler
, not a DragGestureHandler
.
list.js
should work as should drag.js
.
Are you running it in the example app or in your own app? I recommend you first check it works in the example to eliminate issues/wrong config.
And you should pull again and rebuild + change your manifest to match the example's
Awesome work! Looking forward to seeing this merged soon.
I have tried something similar on iOS long time ago but I finally gave up https://github.com/neiker/react-native-drag-n-drop
Hey guys ! I'm really looking for this adding to RNGH ! Thanks a lot for your work @ShaMan123, hope it will be merge soon !
Thank you and looking forward to the new feature soon!
Updated from origin, build passes
fixed a bunch of edge case bugs
I think android is ready for roll out
Would this support web too?
Would this support web too?
@nandorojo Why not? It can wrap around react-dnd
That would be awesome
@ShaMan123 would it be possible to move this PR into a standalone npm package, which uses gesture handler as a peer dependency? That way, you could get community support and testing to help get this merged.
It doesn't seem likely that this will get merged as-is right now, but I'd love to get to use it in my app. I think making it a separate package (like native-dnd
) would be awesome.
What do you think?
I think it isn't feasible. The code can't be separated from the core. And can't be patched together. There is logic that changed. You could PR my fork and I'll merge it. I think this is worth working on to support ios.
בתאריך יום ד׳, 19 במאי 2021, 15:31, מאת Fernando Rojo < @.***>:
@ShaMan123 https://github.com/ShaMan123 would it be possible to move this PR into a standalone npm package, which uses gesture handler as a peer dependency? That way, you could get community support and testing to help get this merged.
It doesn't seem likely that this will get merged as-is right now, but I'd love to get to use this. I think making it a separate package (like native-dnd) would be awesome.
What do you think?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/software-mansion/react-native-gesture-handler/pull/963#issuecomment-844058932, or unsubscribe https://github.com/notifications/unsubscribe-auth/AIGAW4OW25HSYEEDKHAFZFDTOOVTDANCNFSM4KTI6WOQ .
I see. How far along is it? Is it all working for you?
Android works completely. iOS isn't supported. Clone the fork and run the example app
In
Example/draggable
index.js
is a simplePanGestureHandler
, not aDragGestureHandler
.list.js
should work as shoulddrag.js
. Are you running it in the example app or in your own app? I recommend you first check it works in the example to eliminate issues/wrong config.
+1 Let's get this merged in!
EDITED 22/05/21
Motivation #928
PanGestureHandler
-> usingPanGestureHandler
requires a lot of boilerplate to get it to function as a synthetic drag and drop handler (I've tried it rn-drag-drop).FlatList
is a KILLER).react-native-gesture-handler
aims to be a plug and play library, this is why I think drag and drop gesture handling is essential.Changes
I've added 2 new handlers:
DragGestureHandler
andDropGestureHandler
both of them extendPanGestureHandler
. I have made adaptions mainly toGestureHandlerOrchestrator
in the android native code and added examples underDrag & Drop
andDrag & Drop in FlatList
. In addition I've revived the native android example, this was done by adjusting the gesture handler registry and mocking a root view.The only thing out of scope is this fix, which fixes passing down the wrong
handlerTag
to native making relations config wrong forNativeViewGestureHandler
. https://github.com/software-mansion/react-native-gesture-handler/pull/963/files#diff-6eb54a5e8a566ff2be948cdfe0abb5f4Logic
Gesture handling is in progress.
PanGestureHandler
super class ofDragGestureHandler
receives events. It is in charge of moving fromState.UNDETERMINED
toState.BEGAN
andState.ACTIVE
based on it's own logic. Once active,DragGestureHandler
begins dragging. From this point on theGestureHandlerOrchestrator
receives aDragEvent
which is first adapted to aMotionEvent
and delivered to all handlers. This is done to activateDropGestureHandlers
(DropGestureHandler
is the same asDragGestureHandler
in terms ofPanGestureHandler
responsibilities), run simultaneous handlers and cancel the rest. Then theDragEvent
is delivered to all handlers,DropGestureHandlers
first, then the rest. ExtractingDropGestureHandlers
is done for each event to obtain the top most handler. IfDropGestureHandlers
are extracted the top most will be activated notifying the other drag/drop handlers with an appropriateaction
.Multi Window
Android supports multi window. The
AndroidManifest.xml
file needs to be edited to get this working. To persist the same behavior I had to add some logic to bridge the framework not dispatching drag events back to the app that started the drag gesture, leavingDragGestureHandler
unaware of interactions withDropGestureHandlers
. So, I've added a small broadcasting mechanism that broadcasts changes of the dragaction
to the source app. To test this I suggest running bothAndroidNativeExample
andExample
side by side.Simultaneous Handlers
There is a caveat regarding simultaneous handlers. A drag event (on android) has only one pointer so simultaneous handling with
RotationGestureHandler
orPinchGestureHandler
won't work unfortunately. PassingDragGestureHandlers
before the event begins will join them to the drag event and add them to the drag shadow. See example.Props
number | number[] | null
, if aDragGestureHandler
and aDropGestureHandler
share one type they can interact.DragGestureHandler props
DropGestureHandler
on drop via gesture event.react-native-gesture-handler.d.ts
dragMode
- handles the visibilty ofDragGestureHandler
while draggingmove
move-restore
- after drop occurs, restores visibility to the DragGestureHandler's viewcopy
none
shadow
=component | element | tag | null
to render view while draggingmerged asshadowEnabled
dragMode='none'
shadowConfig
- control position, opacity, margin, etc. Drag shadow can update during a drag only fornougat
and higher.Events
Extending
PanGestureHandler
event.https://github.com/software-mansion/react-native-gesture-handler/pull/963#issuecomment-588223553
I believe iOS will be much easier to implement.
Please consider adding this to the road map. Drag gesture handling is the missing piece of RNGH!