Open MatiPl01 opened 3 months ago
Hi! I've looked into your repro. The thing is, on iOS Gesture Handler uses native recognizers and in case of ScrollView
it has about ±150ms
window in which pan gesture will be recognized as scroll. I don't think there's much that we can do about it 😞 (cc @j-piasecki).
Before this time elapses, the Pan gesture calls just the onTouchesDown and onBegin callbacks and no other callback is called later on
That's strange, even on the video that you've attached I can see that you get both, onTouchesCancelled
and onFinalize
callbacks. Moreover, onFinalize
has second parameter, representing if gesture ended successfully, or not. In my case I get false
:
https://github.com/user-attachments/assets/83ec05b3-6180-4bb3-964a-ccd916639813
As a side note, you can simplify your component like this:
<ScrollView contentContainerStyle={styles.content}>
<GestureDetector gesture={panGesture}>
<Animated.View style={[styles.box, animatedStyle]} />
</GestureDetector>
</ScrollView>
Hi! I've looked into your repro. The thing is, on iOS Gesture Handler uses native recognizers and in case of
ScrollView
it has about±150ms
window in which pan gesture will be recognized as scroll. I don't think there's much that we can do about it 😞 (cc @j-piasecki).Before this time elapses, the Pan gesture calls just the onTouchesDown and onBegin callbacks and no other callback is called later on
That's strange, even on the video that you've attached I can see that you get both,
onTouchesCancelled
andonFinalize
callbacks. Moreover,onFinalize
has second parameter, representing if gesture ended successfully, or not. In my case I getfalse
:Nagranie.z.ekranu.2024-08-16.o.11.46.53.mov As a side note, you can simplify your component like this:
<ScrollView contentContainerStyle={styles.content}> <GestureDetector gesture={panGesture}> <Animated.View style={[styles.box, animatedStyle]} /> </GestureDetector> </ScrollView>
onFinalize
and onTouchesCancelled
are fired only after you release the finger but (at least to me) they should be called before releasing the finger.
See how this can be problematic on the following recording. The ScrollView recognizes a gesture but the pan gesture doesn't call any of callbacks when the ScrollView starts handling pan:
https://github.com/user-attachments/assets/3ab0ce87-67c0-416b-8232-ed6c760eb3ce
I got it working by using the Manual gesture which I can cancel manually when I know that the pan gesture would not be handled but still it'd better if pan gesture could be handled after scroll. I understand that this might be not possible on iOS, though, so we can close this issue if nothing more can be done.
As a side note, you can simplify your component like this
Yeah, I know I can simplify code but this is just a repro and I copy-pasted code from my other project (where I need 2 separate components), did some cleanup and didn't care about the simplest implementation.
(...) but still it'd better if pan gesture could be handled after scroll.
I don't think it is something that we will be able to achieve right now 😞 As you can see, there's no touchesMoved
nor onChange
callback, so it might be hard to manipulate scroll without access to them.
I understand that this might be not possible on iOS, though, so we can close this issue if nothing more can be done.
While I can't see good solution to this problem, maybe there is one. Please leave it open until @j-piasecki responds - then we can either close it, or try something else 😅
but still it'd better if pan gesture could be handled after scroll.
The problem here is that the scroll is still technically active (if you set bounces={false}
on the ScrollView, the issue is gone. The weird thing here is that UIKit calls onTouchesBegan
, where we trigger onTouchesDown
and onBegin
callbacks, but it doesn't do anything else. From what I was able to find, it doesn't in any way inform us that the gesture got effectively canceled.
I think it's because we're in Possible
state, so it assumes no actions were done. If that's true, then it's a weird side effect of mapping UIKit states to RNGH states.
As for your use case, wouldn't moving the highlighting logic to onStart
work, since it's not triggered while the scroll is still active? You could try combining it with activateAfterLongPress
.
As for the issue, I think we can keep it open as it should be fixable. The relevant info must exist somewhere since the pan recognizer receives down
event but doesn't receive any subsequent move
events. It's just a matter of finding it, or figuring out that Apple in all it's generosity decided that we mere developers aren't worthy enough to access it.
but still it'd better if pan gesture could be handled after scroll.
The problem here is that the scroll is still technically active (if you set
bounces={false}
on the ScrollView, the issue is gone. The weird thing here is that UIKit callsonTouchesBegan
, where we triggeronTouchesDown
andonBegin
callbacks, but it doesn't do anything else. From what I was able to find, it doesn't in any way inform us that the gesture got effectively canceled.I think it's because we're in
Possible
state, so it assumes no actions were done. If that's true, then it's a weird side effect of mapping UIKit states to RNGH states.As for your use case, wouldn't moving the highlighting logic to
onStart
work, since it's not triggered while the scroll is still active? You could try combining it withactivateAfterLongPress
.As for the issue, I think we can keep it open as it should be fixable. The relevant info must exist somewhere since the pan recognizer receives
down
event but doesn't receive any subsequentmove
events. It's just a matter of finding it, or figuring out that Apple in all it's generosity decided that we mere developers aren't worthy enough to access it.
I wanted to start the item scale change animation when it is touched with a slight delay (I used withDelay
inside the onTouchesDown
callback to start the animation after a slight delay and cancelled the animation if onTouchesUp
or onTouchesCancelled
was called).
I used the Pan gesture together with the activateAfterLongPress
function but I wanted to keep the scale animation separate. When the Pan gesture was activated, the onUpdate
function started being called with translation offsets (onUpdate
starts being called right after onStart
, so I cannot move my logic to onStart
as the scale animation must begin some time before).
I would try to experiment with activateAfterLongPress
a bit more. Maybe I can just activate the Pan gesture earlier, move the scale animation to onStart
and ignore updates from onUpdate
as long as the scale animation is not finished.
Thank you @m-bert and @j-piasecki for your explanations!
Description
Pan gesture works usually fine inside a
ScrollView
or other component except some cases, when I try to drag an item a while after scrolling the scrollable parent container. I would expect the Pan gesture to activate in such a case as well but instead, I have to wait for a noticeable amount of time until it works again. Before this time elapses, the Pan gesture calls just theonTouchesDown
andonBegin
callbacks and no other callback is called later on (if the gesture cannot be handled, I would expect to just receive theonFinalize
callback call to handle such a case).I noticed the problem only on iOS (simulator and real device).
Example recording
https://github.com/user-attachments/assets/87f6549c-f1e4-411d-a6ae-bb0b835f43b8
Steps to reproduce
main
branchSnack or a link to a repository
https://github.com/MatiPl01/gesture-handler-issues
Gesture Handler version
2.18.1
React Native version
0.74.5
Platforms
iOS
JavaScript runtime
Hermes
Workflow
React Native (without Expo)
Architecture
New and Old
Build type
Debug mode
Device
iOS simulator, real device
Device model
tested on iPhone 15 Pro (real device, simulator)
Acknowledgements
Yes