Closed Svarto closed 3 years ago
First thing I see: you need to use useRef (hook, for function) instead of createRef (imperative, for class).
@MoOx thanks for the reply and having a look! Did you get it to work?
I tried with your edits in my local test environment (as mentioned in the bug report, steps to reproduce), and it still does not work with useRef instead of createRef.
I can't say I have a thing totally working because my setup is a bit more complex but I have a working PanGestureHandler (a list) with multiple nested LongPressGestureHandler (manual handles to star dragging) - but in my situation, I can't have the ScrollView to be usable when you are trying to scroll from the PanGestureHandler are. I tried various waitFor/simultaneousHandlers but I don't have a fully working example yet.
That's exactly what I'm trying to do, I don't need the Scrollview to be active while dragging. Only when they have not activated / are in use...
I'm confused what I'm doing wrong, I tried nesting them in the reverse order too and all sort of combination of waitFor but can't get it to work.
Sent from ProtonMail mobile
-------- Original Message -------- On 13 Jan 2021, 17:45, Max Thirouin wrote:
I can't say I have a thing totally working because my setup is a bit more complex but I have a working PanGestureHandler (a list) with multiple nested LongPressGestureHandler (manual handles to star dragging) - but in my situation, I can't have the ScrollView to be usable when you are trying to scroll from the PanGestureHandler are. I tried various waitFor/simultaneousHandlers but I don't have a fully working example yet.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.
Try this patch https://github.com/software-mansion/react-native-gesture-handler/commit/0b0fabc96da1d585a740da6476123ecd74a22fec It hasn't been released yet.
Try this patch 0b0fabc It hasn't been released yet.
hmm, no difference for me. i applied it and restarted with expo start -c
to clear cache...
Ok if I am correct here is what I got working:
minDurationMs={0}
for LongPressGestureHandler)@MoOx hmm, damn it just doesn't work for me. Once LongPressGestureHandler activates, then the PanGestureHandler deactivates and stops working. Somehow the PanGestureHandler also activates before LongPressGestureHandler (i.e. ignores waitFor). It is so weird...
This is the code I am using now, replicating what you just detailed out.
import React from "react";
import { View, Image } from "react-native";
import {
PanGestureHandler,
LongPressGestureHandler,
ScrollView,
} from "react-native-gesture-handler";
import Animated, {
useAnimatedStyle,
useAnimatedGestureHandler,
useSharedValue,
} from "react-native-reanimated";
export default function App() {
const imageSize = 50;
const scrollRef = React.useRef(null);
const longPressRef = React.useRef(null);
const panRef = React.useRef(null);
const y = useSharedValue(0);
const x = useSharedValue(0);
const onGestureEvent = useAnimatedGestureHandler({
onStart: (event, ctx) => {
ctx.offsetX = x.value;
},
onActive: (event, ctx) => {
y.value = event.translationY;
x.value = event.translationX + ctx.offsetX;
},
});
const style = useAnimatedStyle(() => ({
position: "absolute",
top: 0,
left: 0,
width: imageSize,
height: imageSize,
transform: [{ translateX: x.value }, { translateY: y.value }],
}));
return (
<View
style={{
flex: 1,
paddingTop: 100,
height: 300,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
}}
>
<ScrollView
ref={scrollRef}
horizontal={true}
showsHorizontalScrollIndicator={false}
style={{ positon: "relative", height: imageSize, borderWidth: 1 }}
contentContainerStyle={{ width: imageSize * 3 }}
>
<PanGestureHandler
ref={panRef}
simultaneousHandlers={scrollRef}
waitFor={longPressRef}
onHandlerStateChange={({ nativeEvent }) =>
console.log("PANGESTURE ", nativeEvent.state)
}
{...{ onGestureEvent }}
>
<Animated.View>
<LongPressGestureHandler
ref={longPressRef}
minDurationMs={0}
simultaneousHandlers={panRef}
onHandlerStateChange={({ nativeEvent }) => {
console.log("LONG PRESS", nativeEvent.state);
console.log("LONG PRESS, PAN GESTURE SHOULD NOW ACTIVATE");
}}
>
<Animated.View
style={[
{
position: "absolute",
top: 0,
left: 0,
},
style,
]}
>
<Image
source={require("./assets/example.jpg")}
style={{ width: imageSize, height: imageSize }}
/>
</Animated.View>
</LongPressGestureHandler>
</Animated.View>
</PanGestureHandler>
</ScrollView>
</View>
);
}
Actually I said something wrong: in my case I don't use waitFor on the Pan, because I just cannot (I have multiple LongPress and I don't know the one I should for until you press it... so I use a state to say "go for it" that I use in my onGestureHandler before doing my stuff.
@MoOx I see, how d you set the state and have the PanGestureHandler activate without the user "lifting" the finger? I tried with the below, the problem is that the state correctly flips to true and activates the PanGestureHandler but only after I "lift" my finger and basically stop the LongPressGestureHandler.
Snippet (note the enabled on PanGestureHandler and the onGestureEvent state flipping active to true):
<PanGestureHandler
ref={panRef}
enabled={active}
waitFor={longPressRef}
onHandlerStateChange={({ nativeEvent }) =>
console.log("PANGESTURE ", nativeEvent.state)
}
{...{ onGestureEvent }}
>
<Animated.View>
<LongPressGestureHandler
ref={longPressRef}
minDurationMs={1000}
maxDist={10}
onGestureEvent={() => setActive(true)}
onHandlerStateChange={({ nativeEvent }) => {
console.log("LONG PRESS", nativeEvent.state);
console.log("LONG PRESS, PAN GESTURE SHOULD NOW ACTIVATE");
}}
>
Don't use enabled, instead edit your onGesture/onHandlerStateChange to do (or not) your logic.
And put back simultaneousHandlers={scrollRef}
so the scrollview can work too.
I have some minor perf issue with my solution that involve a state but I will try to publish something when this is sorted out.
I was shocked to not be able to find such a trivial problem: sortable list inside a scrollview that can be sorted with just tiny handle (very common thing on sortable list)...
@Svarto did you solved this ?. I'm having the same issue
This issue was not active for some time so I'm closing it. If you need further help please reply.
For anyone coming across something like this in the future, this is how I solved it:
Make a ScrollView component and set its scrollEnabled
to your trigger value:
const scrollViewRef = useRef(null);
const [allowedDragId, setAllowedDragId] = useState<string | null>(null);
const handleDragStart = (id: string) => {
setAllowedDragId(id);
}
const handleDragEnd = () => {
setAllowedDragId(null);
}
return (
<ScrollView
ref={scrollViewRef}
scrollEnabled={allowedDragId === null}
>
{LOCATIONS.map((location, index) => (
<DraggableView
scrollViewRef={scrollViewRef}
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
allowedDragId={allowedDragId}
/>
))}
</ScrollView>
);
In your draggable component, call onDragStart()
when you want to allow a component to be draggable. In the gestureHandler, filter on the trigger value from the previous step:
const [isDragging, setDragging] = useState(false);
const eventHandler = useAnimatedGestureHandler({
onStart: (event, ctx) => {
if (props.allowedDragId === props.location.id) {
runOnJS(setDragging)(true);
}
},
onActive: (event, ctx) => {
if (isDragging) {
// dragging code
},
onEnd: (event, ctx) => {
if (isDragging) {
// drag end code
runOnJS(setDragging)(false);
runOnJS(props.onDragEnd)();
}
},
});
return (
<Animated.View style={animatedStyle}>
<PanGestureHandler
onGestureEvent={eventHandler}
simultaneousHandlers={props.scrollViewRef}
>
<Animated.View>
<CustomView onLongPress={() => props.onDragStart(props.location.id)} />
</Animated.View>
</PanGestureHandler>
</Animated.View>
);
Pass scrollViewRef
to the PanGestureHandler
simultaneousHandlers prop.
You can now enable and disable dragging your draggable component without having to lift your finger off the screen.
Description
Adding the option that PanGestureHandler waitFor a LongPressGestureHandler does not work, the PanGestureHandler activates directly. And once LongPressGestureHandler activates, PanGestureHandler deactivates even with simultanousHandler setup according to docs.
Let me know if I have done anything incorrectly, but I have only followed the docs to the best of my ability combining waitFor and simultaneousHandlers...
Screenshots
Steps To Reproduce
expo init
)expo install react-native-gesture-handler && npm install react-native-reanimated@2.0.0-rc.0
)plugins: ['react-native-reanimated/plugin'],
)expo start -c
)Expected behavior
The PanGestureHandler should waitFor the LongPressGestureHandler to exit the "BEGIN" state before activating, and stay activated once the LongPressGestureHandler activates according to simultaneousHandlers.
Actual behavior
The PanGestureHandler ignores waitFor and simultaneousHandler and activates before LongPressGestureHandler, and deactives once LongPressGestureHandler activates.
Snack or minimal code example
Package versions