Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Touchable] How to stopPropagation touch event #1046

Closed
magicismight opened this issue Apr 28, 2015 · 33 comments
Closed

[Touchable] How to stopPropagation touch event #1046

magicismight opened this issue Apr 28, 2015 · 33 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@magicismight
Copy link
Contributor

I have a ScrollView which contains a View inside.
When I move touch on the View, It will scroll the ScrollView too.
I woner is there a way to stopPropagation just like the DOM event does.
I have tried to set PanResponder like this,but It didn`t work

PanResponder.create({
  onStartShouldSetPanResponder:  function () {
    return false;
  },
  onStartShouldSetPanResponderCapture: function () {
    return false;
  },
  onMoveShouldSetPanResponder:  function () {
    return false;
  },
  onMoveShouldSetPanResponderCapture: function () {
    return false;
  },
  onPanResponderTerminationRequest: function () {
    return false;
  }
});
@joewood
Copy link

joewood commented May 30, 2015

Having the same issue. I'm wondering if ShouldCapture events should return true if the movement is more horizontal than vertical. The documents are not great for the PanResponder API.

@brentvatne brentvatne changed the title How to stopPropagation touch event [Touchable] How to stopPropagation touch event May 30, 2015
@tadeuzagallo tadeuzagallo self-assigned this May 30, 2015
@ghost
Copy link

ghost commented Aug 4, 2015

Thank you for reporting this issue and appreciate your patience. We've notified the core team for an update on this issue. We're looking for a response within the next 30 days or the issue may be closed.

@ericvicenti
Copy link
Contributor

PanResponder.create({ will return an object, and you need to render a view with the responder handlers on it. For exmple:

componentWillMount: function() {
  this.gesture = PanResponder.create({ ... });
}
render: function() {
  return (
    <View {...this.gesture.panHandlers} ... />
  );
},

preventDefault does not enable the touch responsiveness we want on native mobile. To make actions clear to the user, components should visibly respond for a given touch, and give up responder if something else needs it. Although the touch responder API isn't perfect, it should work for most things.

Can you be more specific about what you are trying to do? Maybe post a minimal example of the issue on rnplay.org?

If you have any improvements to the gesture guide or the pan responder docs, feel free to make a pull request!

@brentvatne
Copy link
Collaborator

@ericvicenti - I've had this issue myself as well - for example:

screen shot 2015-09-10 at 10 43 13 am

Inside of the horizontal ScrollView, at the bottom of each page there is a footer that can be pulled upwards. If you start pulling this up (onStartShouldSetPanResponder returns true) then the ScrollView should not do respond to any movement. The only solution I have for this right now is to lock the ScrollView when the gesture begins, and unlock it when it's released. There is a slight problem with this solution still because if you do just the right gesture so that it scrolls the ScrollView a little bit before setting the responder and locking the ScrollView, you end up in a weird state where you're locked in between pages. To handle this, I need to track the active page in the ScrollView and scroll it back to the right position when I lock it.

The best solution would be to just be able to have the PanResponder become responder and block ScrollView. @vjeux mentioned that on Android there is a ~5px delay when the gesture starts before the ScrollView takes over, which gives the PanResponder a chance to respond. Maybe a similar solution is needed for iOS.

@jukkatupamaki
Copy link

While trying to move a SliderIOS's knob, Navigator starts the swipe back gesture at the same time. Using PanResponder to catch the touch start doesn't seem to help.

propagation-stop-bug

componentWillMount: function() {
    this._panResponder = PanResponder.create({
        onStartShouldSetPanResponder: (evt, gestureState) => true,
        onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
        onMoveShouldSetPanResponder: (evt, gestureState) => true,
        onMoveShouldSetPanResponderCapture: (evt, gestureState) => true
    });
}
<SliderIOS {...this._panResponder.panHandlers} />

Even though I use PanResponder to capture the touch event, the onMoveShouldSetPanResponder callback gets called in Navigator (

this._expectingGestureGrant =
this._matchGestureAction(this._eligibleGestures, sceneConfig.gestures, gestureState);
return !!this._expectingGestureGrant;
).

@jukkatupamaki
Copy link

uiexplorer-slider-bug

I just noticed that the same bug exists in the UIExplorer example.

@casperin
Copy link

I had the same problem. This response solved it for me. Essentially same as @tukkajukka's solution above, only with

componentWillMount () {
  this._panResponder = PanResponder.create({
    onPanResponderTerminationRequest: () => false,
    onStartShouldSetPanResponderCapture: () => true,
  });
}

@rameshvishnoi90904
Copy link

I also want to do same thing(Stop Panresponder after a given event).Please Help

@gran33
Copy link

gran33 commented Mar 20, 2016

+1

1 similar comment
@dionysiusmarquis
Copy link

+1

@RD1991
Copy link

RD1991 commented May 6, 2016

Hi ,
I do have the same issue , I am using pan gesture to a view , which is children of a scroll view.
When I drag that view, scroll view drag itself.

I tried using scrollEnabled property , but callback goes into infinite loop.

ezgif com-video-to-gif

@getnashty
Copy link

+1

@bentomas
Copy link

+1

@ericvicenti
Copy link
Contributor

Ideally, once something gets the responder, it can prevent others from responding by setting onPanResponderTerminationRequest: () => false,

However, we often have troubles while interacting with touch interactions happening on the main thread, like the iOS slider, or any scroll views. The problem is that javascript cannot immediately reject the responsiveness of the native event, because the main thread must synchronously decide if JS or the scroll view should become responder, and JS can only respond asynchronously.

This is a difficult problem to solve, and is something we have been thinking about for a while. cc @vjeux @sahrens @jordwalke @lelandrichardson. This could be solved in a similar way as @kmagiera is moving animations to the UI thread. Basically we construct and serialize some logic such that these immediate operations can be resolved without waiting for the JS thread.

@superandrew213
Copy link

A workaround for now could be to disable ScrollView onPanResponderGrant then enable onPanResponderRelease

@mjracca
Copy link

mjracca commented Aug 1, 2016

+1

We tried disabling the ScrollView onPanResponderGrant, but if you pan the View (children) too fast, the pan propagates to the ScrollView before the block, so it moves with it.

@mjracca
Copy link

mjracca commented Aug 4, 2016

For everyone having this issue, you can try our current hack (https://github.com/mjracca/react-native-scroll-block).

Blocking the ScrollView wasn't an option for us, so we created a View that doesn't propagate pointer events, without having to block the scroll (basically a UIView that has a UIPanGestureRecognizer)

We also added a blocked prop, because we need that View to be able to propagate the pointer sometimes.

Hope it helps!

@uc-spr
Copy link

uc-spr commented Sep 7, 2016

Hi ,
I do have the same issue , I am using pan gesture to a view , which is children of a scroll view.
When I drag that view, scroll view drag itself.

@dev-xdyang
Copy link

+1

@kiprijonas
Copy link

+1

@clozr
Copy link

clozr commented Oct 12, 2016

    onPanResponderTerminationRequest: () => false,
    onStartShouldSetPanResponderCapture: () => true,

Disables Tap Events.
I have a horizontal pager and inside it I have a ListView which has swipeable rows. The swipeable row also drags the next page view. When I use this code, I can no longer tap on the rows.

@mattisx
Copy link

mattisx commented Nov 15, 2016

+1
Also, related: How to disable parent scrolling when using NavigationPagerPanResponder from NavigationCard (NavigationTransitioner)?

@ericvicenti
Copy link
Contributor

This is an extremely difficult issue to fix, so I've moved it to product pains, so the community can prioritize it properly for the RN team.

If this issue is still important to you, please upvote it here on product pains!

https://productpains.com/post/react-native/improved-scrollview-touch-interactions

@nulleof
Copy link

nulleof commented Nov 15, 2016

I use

this.scrollView.setNativeProps({ scrollEnabled: false }
inside onPanResponderGrant and
this.scrollView.setNativeProps({ scrollEnabled: true }
inside onPanResponderRelease.

this.scrollView is set inside ref:
<ScrollView ref={(c) => { this.scrollView = c; }} >

It works much faster than setting state variable and there is no scroll movement even if you swipe fast.

@7ynk3r
Copy link

7ynk3r commented Nov 15, 2016

@nulleof that may not work well on Android.

@jorelllinsangan
Copy link

I'm currently disabling scrolling in onPanResponderGrant and reenabling in onPanResponderRelease. It does prevent vertical scrolling while I'm swiping my row. The issue I'm running into now is that upon touching my ListView to scroll it, onPanResponderGrant gets called and disables the scrolling. Is there something that I can do for this to not happen?

@jorelllinsangan
Copy link

I managed to figure out a solution to my problem above with this:

onPanResponderMove: Animated.event([null, { dx: this.state.pan.x, }], { listener: (e, {dx, dy}) => this.props.scroll && this.props.scroll(Math.abs(dx) < Math.abs(dy))})

It works but its not perfect. When you swipe and scroll in quick succession, scroll isn't disabled fast enough.

@uriklar
Copy link

uriklar commented Dec 28, 2016

I have an issue with a Picker on top of a View with PanResponder. The view catches my swipes on the picker. Any idea how to solve this?

@yinghuaheal
Copy link

this.scrollView.setNativeProps({ scrollEnabled: false } seems the best solution so far. but FlatList does not have setNativeProps Api.

m4nuC added a commit to m4nuC/cb_ink that referenced this issue Sep 24, 2017
Super hard to get scroll / pan + move working 100% but this is pretty close. Downside is that scroll is disabled on ScrollView.

This discussion may help: facebook/react-native#1046
m4nuC added a commit to m4nuC/cb_ink that referenced this issue Sep 25, 2017
Super hard to get scroll / pan + move working 100% but this is pretty close. Downside is that scroll is disabled on ScrollView.

This discussion may help: facebook/react-native#1046
@brunoreis
Copy link

Is this closed/solved? What is the best solution so far? I've tried the setNativeProps solution but it is not fast enough. If you drag fast the native will respond before and drag a little.

@brunoreis
Copy link

Hey @ericvicenti, I added the comment above and it's showing that I unassigned you from this issue. I have no idea why that is showing. I think I don't even have the permissions to do such thing.

@brentvatne
Copy link
Collaborator

@aqnaruto
Copy link

+1 same issue

@facebook facebook locked as resolved and limited conversation to collaborators Jul 22, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 22, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests