Нет описания

parallax-scroll-view.tsx 1.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  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. import { ThemedView } from '@/components/themed-view';
  10. import { useColorScheme } from '@/hooks/use-color-scheme';
  11. import { useThemeColor } from '@/hooks/use-theme-color';
  12. const HEADER_HEIGHT = 250;
  13. type Props = PropsWithChildren<{
  14. headerImage: ReactElement;
  15. headerBackgroundColor: { dark: string; light: string };
  16. }>;
  17. export default function ParallaxScrollView({
  18. children,
  19. headerImage,
  20. headerBackgroundColor,
  21. }: Props) {
  22. const backgroundColor = useThemeColor({}, 'background');
  23. const colorScheme = useColorScheme() ?? 'light';
  24. const scrollRef = useAnimatedRef<Animated.ScrollView>();
  25. const scrollOffset = useScrollOffset(scrollRef);
  26. const headerAnimatedStyle = useAnimatedStyle(() => {
  27. return {
  28. transform: [
  29. {
  30. translateY: interpolate(
  31. scrollOffset.value,
  32. [-HEADER_HEIGHT, 0, HEADER_HEIGHT],
  33. [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75]
  34. ),
  35. },
  36. {
  37. scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]),
  38. },
  39. ],
  40. };
  41. });
  42. return (
  43. <Animated.ScrollView
  44. ref={scrollRef}
  45. style={{ backgroundColor, flex: 1 }}
  46. scrollEventThrottle={16}>
  47. <Animated.View
  48. style={[
  49. styles.header,
  50. { backgroundColor: headerBackgroundColor[colorScheme] },
  51. headerAnimatedStyle,
  52. ]}>
  53. {headerImage}
  54. </Animated.View>
  55. <ThemedView style={styles.content}>{children}</ThemedView>
  56. </Animated.ScrollView>
  57. );
  58. }
  59. const styles = StyleSheet.create({
  60. container: {
  61. flex: 1,
  62. },
  63. header: {
  64. height: HEADER_HEIGHT,
  65. overflow: 'hidden',
  66. },
  67. content: {
  68. flex: 1,
  69. padding: 32,
  70. gap: 16,
  71. overflow: 'hidden',
  72. },
  73. });