-
-
Notifications
You must be signed in to change notification settings - Fork 955
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
Gesture propagation in nested TapHandlers #1930
Comments
Hi! This is by design - when you touch the screen, all gestures attached to the views underneath the touch point start tracking the pointer, and they continue to track it (and sent touch events) until the gesture finishes. Similarly, I believe that, in your case, using a import React from 'react';
import { StyleSheet, View } from 'react-native';
import {
Gesture,
GestureDetector,
GestureHandlerRootView,
} from 'react-native-gesture-handler';
import Animated, {
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated';
const INITIAL_BG_COLOR = 'gray';
const App: React.FC = () => {
const backgroundColor = useSharedValue(INITIAL_BG_COLOR);
const innerBackgroundColor = useSharedValue(INITIAL_BG_COLOR);
const tapGesture = Gesture.Tap()
.onBegin(() => {
backgroundColor.value = 'red';
})
.onFinalize(() => {
backgroundColor.value = INITIAL_BG_COLOR;
});
const rButtonStyle = useAnimatedStyle(() => {
return {
backgroundColor: backgroundColor.value,
};
}, []);
const innerTapGesture = Gesture.Tap()
.onStart(() => {
console.log('inner tap');
})
.onFinalize(() => {
innerBackgroundColor.value = INITIAL_BG_COLOR;
});
const innerLongPress = Gesture.LongPress()
.minDuration(0)
.onStart(() => {
innerBackgroundColor.value = 'red';
});
const rInnerButtonStyle = useAnimatedStyle(() => {
return {
backgroundColor: innerBackgroundColor.value,
};
}, []);
return (
<View style={styles.container}>
<GestureDetector gesture={tapGesture}>
<Animated.View style={[styles.button, rButtonStyle]}>
<GestureDetector
gesture={Gesture.Simultaneous(innerLongPress, innerTapGesture)}>
<Animated.View style={[styles.innerButton, rInnerButtonStyle]} />
</GestureDetector>
</Animated.View>
</GestureDetector>
</View>
);
};
export default function AppContainer() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<App />
</GestureHandlerRootView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
button: {
height: 200,
borderRadius: 10,
aspectRatio: 1,
backgroundColor: 'gray',
justifyContent: 'center',
alignItems: 'center',
borderWidth: 1,
borderColor: 'black',
},
innerButton: {
height: 100,
borderRadius: 10,
aspectRatio: 1,
backgroundColor: 'gray',
borderWidth: 1,
borderColor: 'black',
},
}); |
I apologize for the late reply. Thank you very much for the solution, it works as I expected. |
I am facing a similar issue where nested GestureDetectors are used as children, making it impossible to implement the simultaneous LongPress solution. Are you aware of any alternative methods to accomplish this feature? Here's the updated reproduction code and an expo snack for reference: https://snack.expo.dev/Zl9l9D9jb import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
const INITIAL_BG_COLOR = 'gray';
const Square: React.FC<{ size: number }> = ({ size, children }) => {
const backgroundColor = useSharedValue(INITIAL_BG_COLOR);
const tapGesture = Gesture.Tap()
.onTouchesDown(() => {
backgroundColor.value = 'red';
})
.onFinalize(() => {
backgroundColor.value = INITIAL_BG_COLOR;
});
const rButtonStyle = useAnimatedStyle(() => {
return {
backgroundColor: backgroundColor.value,
};
}, []);
return (
<GestureDetector gesture={tapGesture}>
<Animated.View style={[styles.button, rButtonStyle, { height: size }]}>{children}</Animated.View>
</GestureDetector>
);
};
const App: React.FC = () => {
return (
<View style={styles.container}>
<Square size={200}>
<Square size={100} />
</Square>
</View>
);
};
export default function AppContainer() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<App />
</GestureHandlerRootView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
button: {
borderRadius: 10,
aspectRatio: 1,
backgroundColor: 'gray',
justifyContent: 'center',
alignItems: 'center',
borderWidth: 1,
borderColor: 'black',
},
}); |
The requirement is the same as #2331, but using the new API. |
You could try something like thisimport React from 'react';
import { StyleSheet, View } from 'react-native';
import {
Gesture,
GestureDetector,
GestureHandlerRootView,
} from 'react-native-gesture-handler';
import Animated, {
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated';
const INITIAL_BG_COLOR = 'gray';
const Square: React.FC<{ size: number; children?: React.ReactNode }> = ({
size,
children,
}) => {
const backgroundColor = useSharedValue(INITIAL_BG_COLOR);
const tapGesture = Gesture.LongPress()
.minDuration(0)
.onStart(() => {
backgroundColor.value = 'red';
})
.onEnd((_, finishedGracefully) => {
if (finishedGracefully) {
console.log('tap', size);
}
})
.onFinalize(() => {
backgroundColor.value = INITIAL_BG_COLOR;
});
const rButtonStyle = useAnimatedStyle(() => {
return {
backgroundColor: backgroundColor.value,
};
}, []);
return (
<GestureDetector gesture={tapGesture}>
<Animated.View style={[styles.button, rButtonStyle, { height: size }]}>
{children}
</Animated.View>
</GestureDetector>
);
};
const App: React.FC = () => {
return (
<View style={styles.container}>
<Square size={200}>
<Square size={100} />
</Square>
</View>
);
};
export default function AppContainer() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<App />
</GestureHandlerRootView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
button: {
borderRadius: 10,
aspectRatio: 1,
backgroundColor: 'gray',
justifyContent: 'center',
alignItems: 'center',
borderWidth: 1,
borderColor: 'black',
},
}); By using The thing you lose in this approach is the cancelation of the gesture after the user holds it for a longer period of time that the |
Description
Hi, first of all, thank you very much for the work you have done with this package. The issue I am experiencing concerns the propagation of tap events from a child TapHandler to the parent.
In the example presented below, two TapHandlers are visible (created with the GestureDetector component).
The goals of the example are:
Platforms
Screenshots
Steps To Reproduce
The child will propagate the tap gesture to the parent.
Expected behavior
Actual behavior
Snack or minimal code example
Package versions
The text was updated successfully, but these errors were encountered: