mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
Refactor MetadataScreen to implement parallax scrolling effect; update scroll handling with useAnimatedScrollHandler for smoother transitions, enhance hero section with animated image, and adjust styles for improved visual dynamics. Replace ScrollView with Animated.ScrollView for better performance.
This commit is contained in:
parent
b46e491afa
commit
dc19bdd253
1 changed files with 80 additions and 27 deletions
|
|
@ -12,6 +12,8 @@ import {
|
|||
Dimensions,
|
||||
Platform,
|
||||
TouchableWithoutFeedback,
|
||||
NativeSyntheticEvent,
|
||||
NativeScrollEvent,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useRoute, useNavigation, useFocusEffect } from '@react-navigation/native';
|
||||
|
|
@ -42,6 +44,7 @@ import Animated, {
|
|||
FadeIn,
|
||||
runOnJS,
|
||||
Layout,
|
||||
useAnimatedScrollHandler,
|
||||
} from 'react-native-reanimated';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import { NavigationProp } from '@react-navigation/native';
|
||||
|
|
@ -220,7 +223,8 @@ const MetadataScreen = () => {
|
|||
// Get genres from context
|
||||
const { genreMap, loadingGenres } = useGenres();
|
||||
|
||||
const contentRef = useRef<ScrollView>(null);
|
||||
// Update the ref type to be compatible with Animated.ScrollView
|
||||
const contentRef = useRef<Animated.ScrollView>(null);
|
||||
const [lastScrollTop, setLastScrollTop] = useState(0);
|
||||
const [isFullDescriptionOpen, setIsFullDescriptionOpen] = useState(false);
|
||||
|
||||
|
|
@ -254,6 +258,12 @@ const MetadataScreen = () => {
|
|||
const logoOpacity = useSharedValue(0);
|
||||
const logoScale = useSharedValue(0.9);
|
||||
|
||||
// Add shared value for parallax effect
|
||||
const scrollY = useSharedValue(0);
|
||||
|
||||
// Create a dampened scroll value for smoother parallax
|
||||
const dampedScrollY = useSharedValue(0);
|
||||
|
||||
// Debug log for route params
|
||||
// logger.log('[MetadataScreen] Component mounted with route params:', { id, type, episodeId });
|
||||
|
||||
|
|
@ -643,14 +653,6 @@ const MetadataScreen = () => {
|
|||
opacity: screenOpacity.value
|
||||
}));
|
||||
|
||||
const heroAnimatedStyle = useAnimatedStyle(() => ({
|
||||
width: '100%',
|
||||
height: heroHeight.value,
|
||||
backgroundColor: colors.black,
|
||||
transform: [{ scale: heroScale.value }],
|
||||
opacity: heroOpacity.value
|
||||
}));
|
||||
|
||||
const contentAnimatedStyle = useAnimatedStyle(() => ({
|
||||
transform: [{ translateY: contentTranslateY.value }],
|
||||
opacity: interpolate(
|
||||
|
|
@ -847,6 +849,57 @@ const MetadataScreen = () => {
|
|||
));
|
||||
}, [metadata?.genres]); // Dependency on metadata.genres
|
||||
|
||||
// Update the heroAnimatedStyle for parallax effect
|
||||
const heroAnimatedStyle = useAnimatedStyle(() => ({
|
||||
width: '100%',
|
||||
height: heroHeight.value,
|
||||
backgroundColor: colors.black,
|
||||
transform: [{ scale: heroScale.value }],
|
||||
opacity: heroOpacity.value,
|
||||
}));
|
||||
|
||||
// Replace direct onScroll with useAnimatedScrollHandler
|
||||
const scrollHandler = useAnimatedScrollHandler({
|
||||
onScroll: (event) => {
|
||||
const rawScrollY = event.contentOffset.y;
|
||||
scrollY.value = rawScrollY;
|
||||
|
||||
// Apply spring-like damping for smoother transitions
|
||||
dampedScrollY.value = withTiming(rawScrollY, {
|
||||
duration: 300,
|
||||
easing: Easing.bezier(0.16, 1, 0.3, 1), // Custom spring-like curve
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Add a new animated style for the parallax image
|
||||
const parallaxImageStyle = useAnimatedStyle(() => {
|
||||
// Use dampedScrollY instead of direct scrollY for smoother effect
|
||||
return {
|
||||
width: '100%',
|
||||
height: '120%', // Increase height for more movement range
|
||||
top: '-10%', // Start image slightly higher to allow more upward movement
|
||||
transform: [
|
||||
{
|
||||
translateY: interpolate(
|
||||
dampedScrollY.value,
|
||||
[0, 100, 300],
|
||||
[20, -20, -60], // Start with a lower position, then move up
|
||||
Extrapolate.CLAMP
|
||||
)
|
||||
},
|
||||
{
|
||||
scale: interpolate(
|
||||
dampedScrollY.value,
|
||||
[0, 150, 300],
|
||||
[1.1, 1.02, 0.95], // More dramatic scale changes
|
||||
Extrapolate.CLAMP
|
||||
)
|
||||
}
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<SafeAreaView
|
||||
|
|
@ -931,23 +984,22 @@ const MetadataScreen = () => {
|
|||
animated={true}
|
||||
/>
|
||||
<Animated.View style={containerAnimatedStyle}>
|
||||
<ScrollView
|
||||
<Animated.ScrollView
|
||||
ref={contentRef}
|
||||
style={styles.scrollView}
|
||||
showsVerticalScrollIndicator={false}
|
||||
onScroll={(e) => {
|
||||
// setLastScrollTop(e.nativeEvent.contentOffset.y); // Remove unused onScroll handler logic
|
||||
}}
|
||||
scrollEventThrottle={16}
|
||||
onScroll={scrollHandler}
|
||||
scrollEventThrottle={16} // Back to standard value
|
||||
>
|
||||
{/* Hero Section */}
|
||||
<Animated.View style={heroAnimatedStyle}>
|
||||
<ImageBackground
|
||||
source={{ uri: metadata.banner || metadata.poster }}
|
||||
style={styles.heroSection}
|
||||
imageStyle={styles.heroImage}
|
||||
resizeMode="cover"
|
||||
>
|
||||
<View style={styles.heroSection}>
|
||||
{/* Use Animated.Image directly instead of ImageBackground with imageStyle */}
|
||||
<Animated.Image
|
||||
source={{ uri: metadata.banner || metadata.poster }}
|
||||
style={[styles.absoluteFill, parallaxImageStyle]}
|
||||
resizeMode="cover"
|
||||
/>
|
||||
<LinearGradient
|
||||
colors={[
|
||||
`${colors.darkBackground}00`,
|
||||
|
|
@ -1005,7 +1057,7 @@ const MetadataScreen = () => {
|
|||
/>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</ImageBackground>
|
||||
</View>
|
||||
</Animated.View>
|
||||
|
||||
{/* Main Content */}
|
||||
|
|
@ -1117,7 +1169,7 @@ const MetadataScreen = () => {
|
|||
<MovieContent metadata={metadata} />
|
||||
)}
|
||||
</Animated.View>
|
||||
</ScrollView>
|
||||
</Animated.ScrollView>
|
||||
</Animated.View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
|
@ -1189,11 +1241,12 @@ const styles = StyleSheet.create({
|
|||
backgroundColor: colors.black,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
heroImage: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
top: '0%',
|
||||
transform: [{ scale: 1 }],
|
||||
absoluteFill: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
heroGradient: {
|
||||
flex: 1,
|
||||
|
|
|
|||
Loading…
Reference in a new issue