-
-
Notifications
You must be signed in to change notification settings - Fork 972
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
Support multi-touch behaviour with panning and scrolling #2622
Comments
Demo showcasing scroll and panning simultaneously. Dragging a list item from iOS's "Reminders" app: Dragging a iOS widget between the different homescreen: |
@j-piasecki can you by any chance confirm that this is in fact currently not possible with the primitives provided by RNGH? |
Here is a snippet i used with to handle simulatneously multiple gestures with native elements, the key is to have the native element as direct child to your gesture detector You can do something like this,
This will handle both gestures simultaneously, I am just using translationX in my myPanGesture gesture so i havent tried yet with others. |
Hi @matis-dk The end result you described is as far as i know only possible to achieve on The code snippet sent by @zebriot is a good example of how you can achieve these results, the key is to wrap your scroll component with Here's another example which works well on Collapsed codeimport React from 'react';
import { StyleSheet, Text, View, ScrollView } from 'react-native';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring,
} from 'react-native-reanimated';
export default function EmptyExample() {
const panActive = useSharedValue(false);
const position = useSharedValue(0);
const panPreviousPosition = useSharedValue(0);
const scrollPreviousPosition = useSharedValue(-1);
const scroll = Gesture.Native()
.onTouchesMove((event) => {
('worklet');
if (!panActive.value) {
return;
}
const scrollPosition = event.allTouches[0].absoluteY;
if (scrollPreviousPosition.value === -1) {
scrollPreviousPosition.value = scrollPosition;
return;
}
const delta = scrollPosition - scrollPreviousPosition.value;
scrollPreviousPosition.value = scrollPosition;
position.value = position.value - delta;
// console.log('delta', delta);
// console.log('position', position.value);
})
.onFinalize(() => {
scrollPreviousPosition.value = -1;
});
const pan = Gesture.Pan()
.activateAfterLongPress(250)
.onStart(() => {
panActive.value = true;
position.value = 0;
})
.onUpdate((e) => {
const delta = e.translationY - panPreviousPosition.value;
position.value += delta;
panPreviousPosition.value = e.translationY;
})
.onFinalize(() => {
position.value = withSpring(0);
panActive.value = false;
panPreviousPosition.value = 0;
scrollPreviousPosition.value = -1;
});
const elementPadding = 21;
const elementFiller = (
<>
{new Array(elementPadding).fill(1).map(() => (
<View style={styles.box} key={Math.random()}>
<Text>Hello World!</Text>
</View>
))}
</>
);
const animation = useAnimatedStyle(() => ({
...styles.highlight,
transform: [
{
translateY: position.value ?? 0,
},
],
}));
return (
<GestureDetector gesture={scroll}>
<ScrollView style={styles.container}>
{elementFiller}
<GestureDetector gesture={pan}>
<Animated.View style={animation}>
<Text>Hello World!</Text>
</Animated.View>
</GestureDetector>
{elementFiller}
</ScrollView>
</GestureDetector>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
box: {
padding: 40,
backgroundColor: 'navy',
justifyContent: 'center',
},
highlight: {
padding: 40,
backgroundColor: 'tomato',
color: 'white',
zIndex: 99,
},
}); But please keep in mind, as this feature works only on Android. updateas of the following PR: #3095, the |
Description
I’m trying to implement something similar to the gesture behaviour on the default list view on iOS. Eg. the “Reminders” app inside iOS.
It consist of a scrollable view with some list item's inside. When you long-press a list item, it lets you rearrange where the item belong. At the surface, this implementation seems quite simple - a ScrollView wrapping around multiple ListItem component's that is using the
Gesture.Pan().activateAfterLongPress(250)
.The code could look something like this
The problem arise when the scrollable list is expanding beyond the device height dimensions. Because if you would like to drag a ListItem to the bottom of the list, then you need to be able to support scrolling while panning (dragging the item around). To support this, iOS implement 2 different scroll behaviors.
I think that bullet 1. is possible by keeping track of the fingers absolute position on the screen, and activate scroll imperatively, when the primary finger is entering hot areas in the top or bottom of the screen.
But bullet 2. doesn't seem to be possible by the primitive provider by RNGH currently.
By default, ScrollView's seems to be dismissed when a pan-gesture is active. The
simultaneousHandlers
prop allow the ScrollView gesture, andGesture.Pan
, to be active simultaneously - but this let the primary finger, pan and scroll at the same time.What seems to be the crux of the problem, is that when a
Gesture.Pan
is active, RNGH is disabling ScrollView gestures globally, and not locally to the current gesture in action. If theGesture.Pan
instead recognized and ignored the scrollview events, for the local pan-gesture in action, it would allow the secondary finger to scroll. What seems to be missing is a way to distingquish between disabling and ignoring ScrollView events for a given gesture.The multi-touch behavior combining pan with the primary finger, and scrolling with secondary finger, is used multiple places inside iOS. E.g when.
I noticed that
Gesture.Native
is able to wrap and listen to events on the ScrollView, but I'm unable to figure out how this can be composed with behavior im describing above.Steps to reproduce
The code could look something like this
Snack or a link to a repository
https://snack.expo.dev/@matis/99d863
Gesture Handler version
2.12.0
React Native version
0.72.4
Platforms
Android, iOS
JavaScript runtime
None
Workflow
None
Architecture
None
Build type
None
Device
None
Device model
No response
Acknowledgements
Yes
The text was updated successfully, but these errors were encountered: