tech-tracker-expo/components/default/ParallaxScrollView.tsx

93 lines
2.4 KiB
TypeScript
Raw Normal View History

2025-01-28 08:19:46 -06:00
import type { PropsWithChildren, ReactElement } from 'react';
2025-01-28 12:56:22 -06:00
import { StyleSheet, ViewStyle, StyleProp } from 'react-native';
2025-01-28 08:19:46 -06:00
import Animated, {
interpolate,
useAnimatedRef,
useAnimatedStyle,
useScrollViewOffset,
} from 'react-native-reanimated';
2025-01-28 12:56:22 -06:00
import { ThemedText, ThemedView } from '@/components/theme/Theme';
2025-01-28 08:19:46 -06:00
import { useBottomTabOverflow } from '@/components/ui/TabBarBackground';
2025-01-28 12:56:22 -06:00
import { Colors } from '@/constants/Colors';
2025-01-28 08:19:46 -06:00
import { useColorScheme } from '@/hooks/useColorScheme';
2025-01-28 12:56:22 -06:00
const HEADER_HEIGHT = 150;
2025-01-28 08:19:46 -06:00
type Props = PropsWithChildren<{
2025-01-28 12:56:22 -06:00
headerImage?: ReactElement;
headerBackgroundColor?: { dark: string; light: string };
headerHeight?: number;
2025-01-28 12:56:22 -06:00
headerTitle?: ReactElement;
2025-01-28 08:19:46 -06:00
}>;
const ParallaxScrollView = ({
2025-01-28 08:19:46 -06:00
children,
2025-01-28 12:56:22 -06:00
headerImage = <ThemedView />,
headerBackgroundColor = { light: Colors.light.accent, dark: Colors.dark.accent },
headerHeight = HEADER_HEIGHT,
2025-01-28 12:56:22 -06:00
headerTitle = <ThemedText />,
}: Props) => {
const scheme = useColorScheme() ?? 'dark';
2025-01-28 08:19:46 -06:00
const scrollRef = useAnimatedRef<Animated.ScrollView>();
const scrollOffset = useScrollViewOffset(scrollRef);
const bottom = useBottomTabOverflow();
const headerAnimatedStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateY: interpolate(
scrollOffset.value,
[-headerHeight, 0, headerHeight],
[-headerHeight / 2, 0, headerHeight * 0.75],
2025-01-28 08:19:46 -06:00
),
},
{
scale: interpolate(scrollOffset.value, [-headerHeight, 0, headerHeight], [2, 1, 1]),
2025-01-28 08:19:46 -06:00
},
],
};
});
return (
<ThemedView style={styles.container}>
<Animated.ScrollView
ref={scrollRef}
scrollEventThrottle={16}
scrollIndicatorInsets={{ bottom }}
2025-01-28 08:45:02 -06:00
contentContainerStyle={{ paddingBottom: bottom }}
>
2025-01-28 08:19:46 -06:00
<Animated.View
style={[
styles.header,
{
backgroundColor: headerBackgroundColor[scheme],
height: headerHeight,
},
2025-01-28 08:19:46 -06:00
headerAnimatedStyle,
2025-01-28 08:45:02 -06:00
]}
>
2025-01-28 08:19:46 -06:00
{headerImage}
2025-01-28 12:56:22 -06:00
{headerTitle}
2025-01-28 08:19:46 -06:00
</Animated.View>
<ThemedView style={styles.content}>{children}</ThemedView>
</Animated.ScrollView>
</ThemedView>
);
};
export default ParallaxScrollView;
2025-01-28 08:19:46 -06:00
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
overflow: 'hidden',
},
content: {
flex: 1,
padding: 32,
gap: 16,
overflow: 'hidden',
},
});