Created
January 29, 2021 14:13
-
-
Save kmagiera/7681158d76e6796affd9ad41ef2c81aa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { ReactNode, RefObject, useEffect } from "react"; | |
import { Dimensions, StyleSheet } from "react-native"; | |
import Animated, { | |
useAnimatedGestureHandler, | |
useAnimatedStyle, | |
useAnimatedReaction, | |
withSpring, | |
scrollTo, | |
withTiming, | |
useSharedValue, | |
runOnJS, | |
} from "react-native-reanimated"; | |
import { | |
PanGestureHandler, | |
PanGestureHandlerGestureEvent, | |
} from "react-native-gesture-handler"; | |
import { | |
animationConfig, | |
COL, | |
getOrder, | |
getPosition, | |
Positions, | |
SIZE, | |
} from "./Config"; | |
interface ItemProps { | |
children: ReactNode; | |
positions: Animated.SharedValue<Positions>; | |
id: string; | |
editing: boolean; | |
onDragEnd: (diffs: Positions) => void; | |
scrollView: RefObject<Animated.ScrollView>; | |
scrollY: Animated.SharedValue<number>; | |
} | |
function getTruePosition(index, from, to) { | |
'worklet'; | |
let move = 0; | |
if (from < to && index > from && index <= to) move -= 1; | |
if (to < from && index >= to && index < from) move += 1; | |
return getPosition(index + move); | |
} | |
const Item = ({ | |
children, | |
positions, | |
index, | |
dragFromIndex, | |
dragToIndex, | |
scrollY, | |
scrollView, | |
onDragEnd, | |
editing, | |
}: ItemProps) => { | |
const inset = { top: 0, bottom: 0}; | |
const containerHeight = | |
Dimensions.get("window").height - inset.top - inset.bottom; | |
const contentHeight = 8 * SIZE;//(Object.keys(positions.value).length / COL) * SIZE; | |
const panning = useSharedValue(false); | |
const translateX = useSharedValue(0); | |
const translateY = useSharedValue(0); | |
useEffect(() => { | |
if (index === dragToIndex.value) { | |
dragFromIndex.value = dragToIndex.value = -1; | |
} | |
}, [index]); | |
const onGestureEvent = useAnimatedGestureHandler< | |
PanGestureHandlerGestureEvent, | |
{ x: number; y: number } | |
>({ | |
onStart: (_, ctx) => { | |
panning.value = true; | |
dragFromIndex.value = dragToIndex.value = index; | |
}, | |
onActive: ({ translationX, translationY }, ctx) => { | |
// dont allow drag if we're done editing | |
if (editing) { | |
translateX.value = translationX; | |
translateY.value = translationY; | |
// 1. We calculate where the tile should be | |
const position = getPosition(index); | |
const newOrder = getOrder( | |
translateX.value + position.x, | |
translateY.value + position.y, | |
16 | |
); | |
dragToIndex.value = newOrder; | |
// // 3. Scroll up and down if necessary | |
// const lowerBound = scrollY.value; | |
// const upperBound = lowerBound + containerHeight - SIZE; | |
// const maxScroll = contentHeight - containerHeight; | |
// const leftToScrollDown = maxScroll - scrollY.value; | |
// if (translateY.value < lowerBound) { | |
// const diff = Math.min(lowerBound - translateY.value, lowerBound); | |
// scrollY.value -= diff; | |
// scrollTo(scrollView, 0, scrollY.value, false); | |
// ctx.y -= diff; | |
// translateY.value = ctx.y + translationY; | |
// } | |
// if (translateY.value > upperBound) { | |
// const diff = Math.min( | |
// translateY.value - upperBound, | |
// leftToScrollDown | |
// ); | |
// scrollY.value += diff; | |
// scrollTo(scrollView, 0, scrollY.value, false); | |
// ctx.y += diff; | |
// translateY.value = ctx.y + translationY; | |
// } | |
} | |
}, | |
onEnd: () => { | |
panning.value = false; | |
translateX.value = translateY.value = 0; | |
runOnJS(onDragEnd)(dragFromIndex.value, dragToIndex.value); | |
}, | |
}); | |
const style = useAnimatedStyle(() => { | |
const scale = withSpring(panning.value ? 1.05 : 1); | |
let position; | |
if (!panning.value && dragFromIndex.value === index) { | |
position = getPosition(dragToIndex.value); | |
} else { | |
position = getTruePosition(index, dragFromIndex.value, dragToIndex.value); | |
} | |
return { | |
position: "absolute", | |
top: 0, | |
left: 0, | |
width: SIZE, | |
height: SIZE, | |
zIndex: withTiming(panning.value ? 100 : 0), | |
transform: [ | |
{ translateX: panning.value ? position.x + translateX.value : withTiming(position.x) }, | |
{ translateY: panning.value ? position.y + translateY.value : withTiming(position.y)}, | |
{ scale }, | |
], | |
}; | |
}); | |
return ( | |
<Animated.View style={style}> | |
<PanGestureHandler onGestureEvent={onGestureEvent}> | |
<Animated.View style={StyleSheet.absoluteFill}> | |
{children} | |
</Animated.View> | |
</PanGestureHandler> | |
</Animated.View> | |
); | |
}; | |
export default Item; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment