12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- import type { PropsWithChildren, ReactElement } from 'react';
- import { StyleSheet } from 'react-native';
- import Animated, {
- interpolate,
- useAnimatedRef,
- useAnimatedStyle,
- useScrollViewOffset,
- } from 'react-native-reanimated';
-
- import { ThemedView } from '@/components/ThemedView';
- import { useBottomTabOverflow } from '@/components/ui/TabBarBackground';
- import { useColorScheme } from '@/hooks/useColorScheme';
-
- const HEADER_HEIGHT = 250;
-
- type Props = PropsWithChildren<{
- headerImage: ReactElement;
- headerBackgroundColor: { dark: string; light: string };
- }>;
-
- export default function ParallaxScrollView({
- children,
- headerImage,
- headerBackgroundColor,
- }: Props) {
- const colorScheme = useColorScheme() ?? 'light';
- const scrollRef = useAnimatedRef<Animated.ScrollView>();
- const scrollOffset = useScrollViewOffset(scrollRef);
- const bottom = useBottomTabOverflow();
- const headerAnimatedStyle = useAnimatedStyle(() => {
- return {
- transform: [
- {
- translateY: interpolate(
- scrollOffset.value,
- [-HEADER_HEIGHT, 0, HEADER_HEIGHT],
- [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75]
- ),
- },
- {
- scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]),
- },
- ],
- };
- });
-
- return (
- <ThemedView style={styles.container}>
- <Animated.ScrollView
- ref={scrollRef}
- scrollEventThrottle={16}
- scrollIndicatorInsets={{ bottom }}
- contentContainerStyle={{ paddingBottom: bottom }}>
- <Animated.View
- style={[
- styles.header,
- { backgroundColor: headerBackgroundColor[colorScheme] },
- headerAnimatedStyle,
- ]}>
- {headerImage}
- </Animated.View>
- <ThemedView style={styles.content}>{children}</ThemedView>
- </Animated.ScrollView>
- </ThemedView>
- );
- }
-
- const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- header: {
- height: HEADER_HEIGHT,
- overflow: 'hidden',
- },
- content: {
- flex: 1,
- padding: 32,
- gap: 16,
- overflow: 'hidden',
- },
- });
|