react-native-modern-elements
Version:
A modern, customizable UI component library for React Native
48 lines (47 loc) • 1.94 kB
JavaScript
import { Extrapolate, interpolate, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withTiming, } from "react-native-reanimated";
const useScrollShadowAnimation = ({ threshold = 5, // very small scroll needed to show shadow
backgroundColor = "#fff", borderWidth = 0.7, borderBottomWidthColors = "rgba(0,0,0,0.2)", } = {}) => {
const scrollY = useSharedValue(0);
const scrollHandler = useAnimatedScrollHandler({
onScroll: (event) => {
scrollY.value = event.contentOffset.y;
},
});
const animatedShadowStyle = useAnimatedStyle(() => {
const opacity = interpolate(scrollY.value, [0, threshold], [0, 0.3], // appear immediately stronger
Extrapolate.CLAMP);
const radius = interpolate(scrollY.value, [0, threshold], [0, 6], // bigger shadow radius quickly
Extrapolate.CLAMP);
const elevation = interpolate(scrollY.value, [0, threshold], [0, 8], // stronger elevation
Extrapolate.CLAMP);
// ✅ zIndex based on scroll
return {
shadowColor: "black",
shadowOpacity: opacity,
shadowRadius: radius,
elevation,
backgroundColor,
zIndex: 10,
};
});
// borderBttom
const borderAnimatedStyle = useAnimatedStyle(() => {
return {
borderBottomWidth: borderWidth, // always same width
borderBottomColor: scrollY.value > 0
? withTiming(borderBottomWidthColors, { duration: 120 }) // when scrolling
: withTiming("transparent", { duration: 120 }), // when not scrolling
};
});
const staticShadowOffset = {
shadowOffset: { width: 0, height: 3 }, // bottom shadow only
};
return {
scrollHandler,
animatedShadowStyle,
staticShadowOffset,
scrollY,
borderAnimatedStyle,
};
};
export default useScrollShadowAnimation;