software-mansion / react-native-gesture-handler

Declarative API exposing platform native touch and gesture system to React Native.
https://docs.swmansion.com/react-native-gesture-handler/
MIT License
6.13k stars 982 forks source link

Pinch Gesture conflicting with Nested Scroll View #2332

Closed rizwan92 closed 1 year ago

rizwan92 commented 1 year ago

Description

I want to make Google map smooth experience using react-native-reanimated and react-native gesture handler

where one View will have 1000 * 1000 size inside Nested Scroll View one for horizontal and another for vertical scroll behaviour

till now everything is fine but i am facing issue when i pinch the entire View using GestureDetector with pinchGesture Handler

Steps to reproduce


  function FamilyTree() {
  const scale = useSharedValue(1);
  const savedScale = useSharedValue(1);
  const pinchGesture = Gesture.Pinch()
    .onUpdate(e => {
      const chnage = savedScale.value * e.scale;
      scale.value = chnage;
    })
    .onEnd(() => {
      savedScale.value = scale.value;
    });

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  console.log('render', animatedStyle);

  return (
    <GestureDetector gesture={pinchGesture}>
      <View className="flex flex-1 bg-slate-300 p-10">
        <View className="flex flex-1 bg-white overflow-hidden border border-blue-600 p-10">
          <Animated.ScrollView
            contentContainerStyle={{
              borderWidth: 1,
              borderColor: '#000',
              padding: 2,
            }}>
            <Animated.ScrollView
              contentContainerStyle={{ borderWidth: 1, borderColor: 'red' }}
              horizontal>
              <Animated.View
                style={[
                  {
                    flex: 1,
                    width: 1000,
                    height: 1000,
                    backgroundColor: 'white',
                    borderWidth: 2,
                    borderColor: 'green',
                    justifyContent: 'center',
                    alignItems: 'center',
                    overflow: 'hidden',
                  },
                  animatedStyle,
                ]}>
                <CircleNode />
                <CircleNode />
                <CircleNode />
                <CircleNode />
              </Animated.View>
            </Animated.ScrollView>
          </Animated.ScrollView>
        </View>
      </View>
    </GestureDetector>
  );
}

Snack or a link to a repository

https://snack.expo.dev/@rizwan92/pinch-with-gesture

Gesture Handler version

2.8.0

React Native version

0.69.1

Platforms

Android

JavaScript runtime

No response

Workflow

React Native (without Expo)

Architecture

Paper (Old Architecture)

Build type

Debug mode

Device

Real device

Device model

Xiomi 11 lite NE Android 12 SKQ1.211006.001

Acknowledgements

Yes

rizwan92 commented 1 year ago

any update?

j-piasecki commented 1 year ago

If you want the gestures to work alongside the native views handling touch by themselves, you need to wrap them with GestureDetector recognizing Native gesture. You will also need to mark them as simultaneous. You also need to wrap your application with GestureHandlerRootView, otherwise GH will not be able to intercept touch events.

Here's how it may look. ```jsx export default function App() { const scale = useSharedValue(1); const savedScale = useSharedValue(1); const pinchGesture = Gesture.Pinch() .onUpdate(e => { const chnage = savedScale.value * e.scale; scale.value = chnage; }) .onEnd(() => { savedScale.value = scale.value; }); const scroll1 = Gesture.Native().simultaneousWithExternalGesture(pinchGesture); const scroll2 = Gesture.Native().simultaneousWithExternalGesture(pinchGesture); const animatedStyle = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }], })); console.log('render', animatedStyle); return ( ); } ```
rizwan92 commented 1 year ago

it still has a lot of glitches it's not smooth, and scrolling horizontally was way too much pain in android

rizwan92 commented 1 year ago

i dont know why this code has more better experience but not good for production

 <GestureDetector gesture={pinchGesture}>
        <View className="flex flex-1 bg-transparent justify-center items-center overflow-hidden shadow-2xl border-slate-200  shadow-black border-8">
          <GestureDetector gesture={nativeGesture}>
            <ScrollView waitFor={pinchRef} showsVerticalScrollIndicator={false}>
              <ScrollView
                horizontal
                waitFor={pinchRef}
                showsHorizontalScrollIndicator={false}>
                <Animated.View
                  style={[
                    {
                      flex: 1,
                      width: '100%',
                      height: '100%',
                      minHeight: Dimensions.get('window').height * 2,
                      minWidth: Dimensions.get('window').width * 2,
                      justifyContent: 'flex-start',
                      alignItems: 'flex-start',
                      // borderWidth: 1,
                      overflow: 'scroll',
                    },
                    animatedStyle,
                  ]}>
                  {data.users.length > 0 && (
                    <Node top node={data.users[0]} level={1} number={1} />
                  )}
                </Animated.View>
              </ScrollView>
            </ScrollView>
          </GestureDetector>
        </View>
      </GestureDetector>
rizwan92 commented 1 year ago

@j-piasecki any update or thought on this ?

j-piasecki commented 1 year ago

I'm not sure what exactly you meant in the previous comments, but in general nesting scroll views to enable panning is not the best solution, especially on Android where, as far as I know, only one of the scroll views can be active so you cannot scroll diagonally.

Using pan gesture along transform property to move the view respectively might be a better solution.

rizwan92 commented 1 year ago

@j-piasecki it would help me to achieve the experience like google Maps?

what would you do if someone asks you to build a google map like solution in react native?

I am building a family tree of users so the user can focus on nodes, zoom it, and scroll diagonally, what is the best way to do this in react native gesture handling?

Screenshot 2022-12-19 at 7 02 46 PM
j-piasecki commented 1 year ago

I think using transform property is a better approach. https://github.com/software-mansion/react-native-gesture-handler/issues/2138 might help you, as it generally tries to accomplish the same thing but with an image.