You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
1.9 KiB
79 lines
1.9 KiB
import type { PropsWithChildren, ReactElement } from 'react'; |
|
import { StyleSheet } from 'react-native'; |
|
import Animated, { |
|
interpolate, |
|
useAnimatedRef, |
|
useAnimatedStyle, |
|
useScrollOffset, |
|
} from 'react-native-reanimated'; |
|
|
|
import { ThemedView } from '@/components/themed-view'; |
|
import { useColorScheme } from '@/hooks/use-color-scheme'; |
|
import { useThemeColor } from '@/hooks/use-theme-color'; |
|
|
|
const HEADER_HEIGHT = 250; |
|
|
|
type Props = PropsWithChildren<{ |
|
headerImage: ReactElement; |
|
headerBackgroundColor: { dark: string; light: string }; |
|
}>; |
|
|
|
export default function ParallaxScrollView({ |
|
children, |
|
headerImage, |
|
headerBackgroundColor, |
|
}: Props) { |
|
const backgroundColor = useThemeColor({}, 'background'); |
|
const colorScheme = useColorScheme() ?? 'light'; |
|
const scrollRef = useAnimatedRef<Animated.ScrollView>(); |
|
const scrollOffset = useScrollOffset(scrollRef); |
|
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 ( |
|
<Animated.ScrollView |
|
ref={scrollRef} |
|
style={{ backgroundColor, flex: 1 }} |
|
scrollEventThrottle={16}> |
|
<Animated.View |
|
style={[ |
|
styles.header, |
|
{ backgroundColor: headerBackgroundColor[colorScheme] }, |
|
headerAnimatedStyle, |
|
]}> |
|
{headerImage} |
|
</Animated.View> |
|
<ThemedView style={styles.content}>{children}</ThemedView> |
|
</Animated.ScrollView> |
|
); |
|
} |
|
|
|
const styles = StyleSheet.create({ |
|
container: { |
|
flex: 1, |
|
}, |
|
header: { |
|
height: HEADER_HEIGHT, |
|
overflow: 'hidden', |
|
}, |
|
content: { |
|
flex: 1, |
|
padding: 32, |
|
gap: 16, |
|
overflow: 'hidden', |
|
}, |
|
});
|
|
|