mirror of
https://github.com/zimplexing/OrionTV.git
synced 2026-02-15 12:24:44 +08:00
88 lines
2.1 KiB
TypeScript
88 lines
2.1 KiB
TypeScript
import type {PropsWithChildren, ReactElement} from 'react';
|
|
import {StyleSheet, useColorScheme} from 'react-native';
|
|
import Animated, {
|
|
interpolate,
|
|
useAnimatedRef,
|
|
useAnimatedStyle,
|
|
useScrollViewOffset,
|
|
} from 'react-native-reanimated';
|
|
|
|
import {ThemedView} from '@/components/ThemedView';
|
|
import {useScale} from '@/hooks/useScale';
|
|
|
|
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 scale = useScale();
|
|
const styles = useParallaxScrollViewStyles();
|
|
|
|
const HEADER_HEIGHT = 125 * scale;
|
|
|
|
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}>
|
|
<Animated.View
|
|
style={[
|
|
styles.header,
|
|
{backgroundColor: headerBackgroundColor[colorScheme]},
|
|
headerAnimatedStyle,
|
|
]}
|
|
>
|
|
{headerImage}
|
|
</Animated.View>
|
|
<ThemedView style={styles.content}>{children}</ThemedView>
|
|
</Animated.ScrollView>
|
|
</ThemedView>
|
|
);
|
|
}
|
|
|
|
const useParallaxScrollViewStyles = function () {
|
|
const scale = useScale();
|
|
return StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
},
|
|
header: {
|
|
height: 125 * scale,
|
|
overflow: 'hidden',
|
|
},
|
|
content: {
|
|
flex: 1,
|
|
padding: 32 * scale,
|
|
gap: 16 * scale,
|
|
overflow: 'hidden',
|
|
},
|
|
});
|
|
};
|