Skip to content

Instantly share code, notes, and snippets.

@kmagiera
Created January 29, 2021 14:13
Show Gist options
  • Save kmagiera/7681158d76e6796affd9ad41ef2c81aa to your computer and use it in GitHub Desktop.
Save kmagiera/7681158d76e6796affd9ad41ef2c81aa to your computer and use it in GitHub Desktop.
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