facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.26k stars 24.34k forks source link

PanResponder does not block ScrollView on iOS #32306

Closed stackcookie1 closed 7 months ago

stackcookie1 commented 3 years ago

Description

The PanResponder does not block the ScrollView on iOS. Android works as it should. No matter with which ShouldSet function you want to prevent the responder from being rejected, the ScrollView above the element scrolls anyway.

React Native version:

  SDKs:
    iOS SDK:
      Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
    Android SDK:
      API Levels: 25, 28, 29, 30
      Build Tools: 28.0.3, 29.0.0, 29.0.2, 30.0.2
      System Images: android-28 | Google Play Intel x86 Atom
  npmPackages:
    react: 17.0.2 => 17.0.2 
    react-native: 0.65.1 => 0.65.1 

Steps To Reproduce

1) Create a view in a ScrollView as a child. 2) Now try to move the finger in the view.

const panResponder = React.useRef(
    PanResponder.create({
      // Ask to be the responder:
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
      onPanResponderTerminationRequest: (evt, gestureState) => false,

      onPanResponderGrant: (evt, gestureState) => {
        // The gesture has started. Show visual feedback so the user knows
        // what is happening!
        // gestureState.d{x,y} will be set to zero now
      },
      onPanResponderMove: (evt, gestureState) => {
        // The most recent move distance is gestureState.move{X,Y}
        // The accumulated gesture distance since becoming responder is
        // gestureState.d{x,y}
      },
      onPanResponderRelease: (evt, gestureState) => {
        // The user has released all touches while this view is the
        // responder. This typically means a gesture has succeeded
      },
      onPanResponderTerminate: (evt, gestureState) => {
        // Another component has become the responder, so this gesture
        // should be cancelled
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // Returns whether this component should block native components from becoming the JS
        // responder. Returns true by default. Is currently only supported on android.
        return true;
      }
    })
  ).current;

<ScrollView>
      <View
        {...panResponder.panHandlers}
        style={{ height: 400, width: 400 }}>
        <Text>Prevent scrolling here</Text>
      </View>
</ScrollView>

Expected Results

Since the PanResponder has control, the ScrollView must not scroll. The event seems to be bubbled.

Snack, code example, screenshot, or link to a repository:

https://snack.expo.dev/fKP048VbJ

stale[bot] commented 2 years ago

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

joshchoo commented 2 years ago

Facing the same issue. My workaround is to disable scrolling on onPanResponderGrant, and restore it on onPanResponderRelease.

natew commented 2 years ago

This is true also on any view, I tried every combination here and nothing can prevent scrolling:

const prevent = (val) => (event) => {
  event.stopPropagation()
  event.preventDefault()
  return val
}
        <View
          onMoveShouldSetResponderCapture={prevent(true)}
          onScrollShouldSetResponder={prevent(true)}
          onScrollShouldSetResponderCapture={prevent(true)}
          onMoveShouldSetResponder={prevent(true)}
          onStartShouldSetResponder={prevent(true)}
          onStartShouldSetResponderCapture={prevent(true)}
          onResponderTerminationRequest={prevent(false)}
          style={{
            width: 100,
            height: 100,
            backgroundColor: 'red',
          }}
        />
ItsGabeReal commented 1 year ago

I'm running into this issue as well.

My workaround is to disable scrolling on onPanResponderGrant, and restore it on onPanResponderRelease.

This is the workaround I've been using, but PanResponder will still terminate if I call scrollTo on the ScrollView.

github-actions[bot] commented 7 months ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

github-actions[bot] commented 7 months ago

This issue was closed because it has been stalled for 7 days with no activity.