Closed GNUGradyn closed 10 months ago
@GNUGradyn I've also added this package to a react-native@0.72.3
project. I can see the onBegin
- onDragEnd
events firing in my console but no movement of the DraggableComponent
.
Like you've explained the DraggableComponent
doesn't actually move or translate onto the Droppable
component. I'm wondering if the latest version is not yet compatible with react-native@0.72.3
? @mgcrea
@GNUGradyn in your example your custom component is lacking the required animatedStyle to actually move it along the drag gesture, you need something like this (tldr. useAnimatedStyle
with transform translateX & translateY):
import { useDraggable } from "@mgcrea/react-native-dnd";
import { Text, View } from "react-native";
import Animated, {
useAnimatedStyle,
withSpring,
} from "react-native-reanimated";
const DraggableComponent = ({ id, data, disabled }) => {
const { offset, setNodeRef, activeId, setNodeLayout, draggableState } = useDraggable({
id,
data,
disabled,
});
const animatedStyle = useAnimatedStyle(() => {
const isActive = activeId.value === id;
return {
opacity: isActive ? 0.9 : 1,
zIndex: isActive ? 999 : 1,
transform: [
{
translateX: isActive ? offset.x.value : withSpring(offset.x.value),
},
{
translateY: isActive ? offset.y.value : withSpring(offset.y.value),
},
],
};
}, [id]);
return (
<Animated.View ref={setNodeRef} onLayout={setNodeLayout} style={animatedStyle}>
<View style={{width: 50, height: 50, backgroundColor:"green"}}>
<Text>DRAG</Text>
</View>
</Animated.View>
);
};
export default DraggableComponent;
@mgcrea I've setup a sample component similar to the snippet you've described above.
But there are no drag callbacks triggered when I try to drag the DraggableCustomComponent
and the block itself doesn't move position on screen.
"dependencies": {
"@mgcrea/react-native-dnd": "^1.4.0",
"react": "18.2.0",
"react-native": "^0.72.3",
"react-native-gesture-handler": "^2.12.0",
"react-native-haptic-feedback": "2.0.3",
"react-native-reanimated": "^3.3.0",
},
Any ideas what could be gone wrong in my component's below? (Although it does seem to be the exact same component code) Or maybe point me in the direction on how I can debug this further?
import {
DndProvider,
DndProviderProps,
Draggable,
DraggableProps,
Droppable,
DroppableProps,
} from '@mgcrea/react-native-dnd';
import React, {useState, type FunctionComponent} from 'react';
import {SafeAreaView, StyleSheet, Text, View, Dimensions} from 'react-native';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
import {runOnJS, useSharedValue} from 'react-native-reanimated';
import DraggableCustomComponent from './drag-n-drop/DraggableComponent';
const ScreenWidth = Dimensions.get('window').width;
const ScreenHeight = Dimensions.get('window').height;
export const DuctPlannerComponent: FunctionComponent = () => {
const [count, setCount] = useState(0);
const dynamicData = useSharedValue({count: 0});
const onDragEnd = () => {
setCount((count) => count + 1);
};
const handleDragEnd: DndProviderProps['onDragEnd'] = ({active, over}) => {
'worklet';
if (over) {
console.log(`Current count is ${active.data.value.count}`);
dynamicData.value = {
...dynamicData.value,
count: dynamicData.value.count + 1,
};
runOnJS(onDragEnd)();
}
};
const handleBegin: DndProviderProps['onBegin'] = () => {
'worklet';
console.log('onBegin');
};
const handleFinalize: DndProviderProps['onFinalize'] = () => {
'worklet';
console.log('onFinalize');
};
const draggableStyle: DraggableProps['animatedStyleWorklet'] = (
style,
{isActive, isActing},
) => {
'worklet';
return {
opacity: isActing ? 0.5 : 1,
backgroundColor: isActive ? 'lightseagreen' : 'seagreen',
};
};
const droppableStyle: DroppableProps['animatedStyleWorklet'] = (
style,
{isActive},
) => {
'worklet';
return {
backgroundColor: isActive ? 'lightsteelblue' : 'steelblue',
};
};
return (
<SafeAreaView style={styles.container}>
<GestureHandlerRootView>
<DndProvider
onBegin={handleBegin}
onFinalize={handleFinalize}
onDragEnd={handleDragEnd}>
<View style={styles.container}>
<Droppable
id="drop"
style={styles.box}
animatedStyleWorklet={droppableStyle}
activeOpacity={1}>
<Text style={styles.text}>DROP</Text>
</Droppable>
<DraggableCustomComponent
id="drag"
data={dynamicData}
style={styles.box}
animatedStyleWorklet={draggableStyle}
/>
{/* The Draggable also did not respond to drag gestures */}
{/* <Draggable
id="drag"
data={dynamicData}
style={styles.box}
animatedStyleWorklet={draggableStyle}>
<Text style={styles.text}>DRAG</Text>
</Draggable> */}
<Text testID="button">count is {count}</Text>
</View>
</DndProvider>
</GestureHandlerRootView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
width: ScreenWidth,
height: ScreenHeight,
alignItems: 'center',
justifyContent: 'center',
},
box: {
margin: 24,
padding: 24,
height: 96,
width: 96,
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'darkseagreen',
},
text: {
color: 'white',
},
});
import {useDraggable} from '@mgcrea/react-native-dnd';
import {Text, View, StyleSheet} from 'react-native';
import Animated, {useAnimatedStyle, withSpring} from 'react-native-reanimated';
const DraggableCustomComponent = ({id, data, disabled}) => {
const {offset, setNodeRef, activeId, setNodeLayout, draggableState} =
useDraggable({
id,
data,
disabled,
});
const animatedStyle = useAnimatedStyle(() => {
const isActive = activeId.value === id;
return {
opacity: isActive ? 0.9 : 1,
zIndex: isActive ? 999 : 1,
transform: [
{
translateX: isActive ? offset.x.value : withSpring(offset.x.value),
},
{
translateY: isActive ? offset.y.value : withSpring(offset.y.value),
},
],
};
}, [id]);
return (
<Animated.View
ref={setNodeRef}
onLayout={setNodeLayout}
style={animatedStyle}>
<View style={styles.box}>
<Text>DRAG 2</Text>
</View>
</Animated.View>
);
};
const styles = StyleSheet.create({
box: {
margin: 24,
padding: 24,
height: 128,
width: 128,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'darkseagreen',
},
});
export default DraggableCustomComponent;
I did encounter issues when building/bundling this library for past releases and did not immediately notice it on my local test setup, for more info see https://github.com/software-mansion/react-native-reanimated/discussions/4979
For now you must use the exact same reanimated version that the one from the lib (currently the latest) or you will encounter version mismatch issues, can you retry your code with @mgcrea/react-native-dnd@1.5.5
and react-native-reanimated@3.4.2
? It should work. Let me know if it does not and I'll investigate further.
I've just published a working demo project on GitHub if you want to check and plan to add more examples to it in the future to help test the lib: https://github.com/mgcrea/react-native-dnd-demo
@mgcrea, yes that's great this works now with @mgcrea/react-native-dnd@1.5.6
based on your example 👏
I've been playing around with the example and assumed a Draggable component would automatically "drop into" a Droppable component. But the Draggable component just snaps back to its starting position in the view. Looking at the docs I didn't see anything calling out how you enable the component to be dropped- https://mgcrea.github.io/react-native-dnd/components/draggable/
Do you plan to add some example of this or could guide me on the implementation?
@mgcrea This is what happens with your latest demo code, the Draggable component snaps back to its starting coordinates (0:0) on the View. I've also played around with a custom Draggable component, which uses a useAnimatedStyle
- https://github.com/mgcrea/react-native-dnd/issues/6#issuecomment-1688940396. I can see that the updater function is transforming the component along the translateX
& translateY
coordinates. But on dragEnd (draggableState.value = 5
) its resetting to starting coordinates - offset.x.value = 0, offfset.y.value = 0
For example in the logs below you can see coordinates when I drag over the drop component, then let go of the DraggableComponennt, which resets to x & y = 0. Instead of dropping at the last coordinate before I let go of the item (offset.x.value = 0, offset.y.value = -0.013319007820699134
)
In the meantime I'll study the reanimated docs to better understand useAnimatedStyle
.
But any help on this would be greatly appreciated.
LOG draggableState.value = 5
LOG isActive = false
LOG activeId.value = null
LOG id = bend-1-key
LOG offset.x.value = 0
LOG offset.y.value = -0.013319007820699134
LOG data.over = {"over":{"id":"drop","data":{"value":{},"_value":{},"_animation":null,"_isReanimatedSharedValue":true},"disabled":false}}
LOG draggableState.value = 5
LOG isActive = false
LOG activeId.value = null
LOG id = bend-1-key
LOG offset.x.value = 0
LOG offset.y.value = 0
LOG data.over = {"over":{"id":"drop","data":{"value":{},"_value":{},"_animation":null,"_isReanimatedSharedValue":true},"disabled":false}}
I see my mistake after reading https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedStyle#returns,
just need to return an empty object when draggableState = END
Although once I drop an item, I can no longer move it again. So it seems there is still a flaw in the logic of the animated style below?
const animatedStyle = useAnimatedStyle(() => {
const isActive = activeId.value === id;
if (isActive && draggableState.value !== 5) {
return {
opacity: isActive ? 0.9 : 1,
zIndex: isActive ? 999 : 1,
transform: [
{
translateX: isActive ? offset.x.value : withSpring(offset.x.value),
},
{
translateY: isActive ? offset.y.value : withSpring(offset.y.value),
},
],
};
} else {
return {};
}
}, [id, offset, activeId, draggableState]);
I've fixed reanimated bundling issues with the 1.6.0
release and everything should correctly works from now on, whatever the final app setup/dependencies is/are.
Feel free to open new issues if you encounter other issues.
@BrianJVarley your problem seems unrelated to this ticket so please open a separate one if you stil encounter issues.
Hello. I implemented UseDraggable as documented. The events are firing but the element is not following the cursor. I have made an MRE here.
https://github.com/GNUGradyn/RnDndMre
Using the provided Draggable component works, but not the custom one in this repo based on the sample on the docs