eletrotupi / tcc/ frontend/components/misc/parallax-scroll-view.tsxe8826b4915d2fdf3653a2557c7d783db8688640d
2.0 KB | 79 lines Raw
1
import type { PropsWithChildren, ReactElement } from 'react';
2
import { StyleSheet } from 'react-native';
3
import Animated, {
4
  interpolate,
5
  useAnimatedRef,
6
  useAnimatedStyle,
7
  useScrollOffset,
8
} from 'react-native-reanimated';
9

10
import { ThemedView } from '@/components/misc/themed-view';
11
import { useColorScheme } from '@/hooks/use-color-scheme';
12
import { useThemeColor } from '@/hooks/use-theme-color';
13

14
const HEADER_HEIGHT = 250;
15

16
type Props = PropsWithChildren<{
17
  headerImage: ReactElement;
18
  headerBackgroundColor: { dark: string; light: string };
19
}>;
20

21
export default function ParallaxScrollView({
22
  children,
23
  headerImage,
24
  headerBackgroundColor,
25
}: Props) {
26
  const backgroundColor = useThemeColor({}, 'background');
27
  const colorScheme = useColorScheme() === 'dark' ? 'dark' : 'light';
28
  const scrollRef = useAnimatedRef<Animated.ScrollView>();
29
  const scrollOffset = useScrollOffset(scrollRef);
30
  const headerAnimatedStyle = useAnimatedStyle(() => {
31
    return {
32
      transform: [
33
        {
34
          translateY: interpolate(
35
            scrollOffset.value,
36
            [-HEADER_HEIGHT, 0, HEADER_HEIGHT],
37
            [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75]
38
          ),
39
        },
40
        {
41
          scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]),
42
        },
43
      ],
44
    };
45
  });
46

47
  return (
48
    <Animated.ScrollView
49
      ref={scrollRef}
50
      style={{ backgroundColor, flex: 1 }}
51
      scrollEventThrottle={16}>
52
      <Animated.View
53
        style={[
54
          styles.header,
55
          { backgroundColor: headerBackgroundColor[colorScheme] },
56
          headerAnimatedStyle,
57
        ]}>
58
        {headerImage}
59
      </Animated.View>
60
      <ThemedView style={styles.content}>{children}</ThemedView>
61
    </Animated.ScrollView>
62
  );
63
}
64

65
const styles = StyleSheet.create({
66
  container: {
67
    flex: 1,
68
  },
69
  header: {
70
    height: HEADER_HEIGHT,
71
    overflow: 'hidden',
72
  },
73
  content: {
74
    flex: 1,
75
    padding: 32,
76
    gap: 16,
77
    overflow: 'hidden',
78
  },
79
});