-
-
Save moxen-dev/8808a943931f755dbd406a67e0d9a316 to your computer and use it in GitHub Desktop.
Bottom Sheet using react navigation gesture handler that produces a android freezing.
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 { usePathname, useSearchParams } from "expo-router"; | |
import { createContext, forwardRef, memo, ReactElement, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react"; | |
import { Dimensions, KeyboardAvoidingView, StyleSheet, View } from "react-native"; | |
import { Gesture, GestureDetector } from 'react-native-gesture-handler'; | |
import Animated, { Extrapolate, interpolate, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated'; | |
import { React } from "sentry-expo"; | |
import { useStore } from "../../../../store"; | |
import colors from "../../../../styles/colors"; | |
const { height: SCREEN_HEIGHT } = Dimensions.get("window"); | |
const MAX_TRANSLATE_Y = -SCREEN_HEIGHT + 50; | |
export default function CustomBottomSheetComponent() { | |
const [content, setContent] = useState<ReactElement>(<View></View>); | |
const pathname = usePathname(); | |
const searchParams = useSearchParams(); | |
const ref = useRef<BottomSheetPanelRefProps>(null); | |
const setBottomSheet = useStore((state) => state.setBottomSheet); | |
const open = useCallback((content: ReactElement, height: number) => { | |
if (typeof height !== "number") height = 0; | |
ref?.current?.scrollTo(-SCREEN_HEIGHT * height); | |
setContent(content); | |
}, []); | |
const close = useCallback(() => { | |
ref?.current?.scrollTo(SCREEN_HEIGHT); | |
}, []); | |
useEffect(() => { | |
setBottomSheet(open, close); | |
}, []); | |
useEffect(() => { | |
close(); | |
}, [pathname, searchParams]); | |
return ( | |
<BottomSheetPanel ref={ref}> | |
{content} | |
</BottomSheetPanel> | |
); | |
}; | |
type BottomSheetPanelProps = { | |
children: ReactElement; | |
}; | |
type BottomSheetPanelRefProps = { | |
scrollTo: (destination: number) => void; | |
}; | |
const BottomSheetPanel = forwardRef<BottomSheetPanelRefProps, BottomSheetPanelProps>(({ children }, ref) => { | |
const translateY = useSharedValue(0); | |
const context = useSharedValue({ y: 0 }); | |
const scrollTo = useCallback((destination: number) => { | |
'worklet'; | |
translateY.value = destination; | |
}, []); | |
useImperativeHandle(ref, () => ({ scrollTo }), [scrollTo]); | |
const gesture = useMemo(() => Gesture.Pan() | |
.onStart(() => { | |
context.value = { y: translateY.value }; | |
}) | |
.onUpdate((event) => { | |
translateY.value = event.translationY + context.value.y; | |
translateY.value = Math.max(translateY.value, MAX_TRANSLATE_Y); | |
}) | |
.onEnd(() => { | |
if (translateY.value > -SCREEN_HEIGHT / 3) { | |
scrollTo(0); | |
} else if (translateY.value < -SCREEN_HEIGHT / 1.5) { | |
scrollTo(MAX_TRANSLATE_Y); | |
}; | |
}), []); | |
const animatedBottomSheetStyle = useAnimatedStyle(() => { | |
const borderRadius = interpolate( | |
translateY.value, | |
[MAX_TRANSLATE_Y + 50, MAX_TRANSLATE_Y], | |
[25, 5], | |
Extrapolate.CLAMP, | |
); | |
return { | |
borderRadius, | |
transform: [{ | |
translateY: translateY.value | |
}], | |
}; | |
}); | |
// useEffect(() => { | |
// scrollTo(-SCREEN_HEIGHT / 3); | |
// }, []); | |
if (!children) return null; | |
return ( | |
<GestureDetector gesture={gesture}> | |
<Animated.View style={[styles.container, animatedBottomSheetStyle]}> | |
<View style={styles.line} /> | |
{children} | |
</Animated.View> | |
</GestureDetector> | |
); | |
}); | |
const styles = StyleSheet.create({ | |
container: { | |
backgroundColor: colors.black, | |
height: SCREEN_HEIGHT, | |
width: "100%", | |
position: "absolute", | |
top: SCREEN_HEIGHT, | |
borderRadius: 25, | |
}, | |
line: { | |
backgroundColor: colors.Slate[500], | |
width: 75, | |
height: 4, | |
alignSelf: "center", | |
marginVertical: 15, | |
borderRadius: 2, | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment