It's possible to animate the Native Stack header, but since only Animated
components accept animated styles in Reanimated 2, you'd probably have to create a new component for the header (an Animated.Something
)...
We can achieve this by using the header
option, which can be found here.
A simple example built with Expo:
import React from "react";
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View } from "react-native";
import { NavigationContainer, useNavigation } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import Animated, {
useSharedValue,
useAnimatedStyle,
useAnimatedScrollHandler,
interpolateColor,
} from "react-native-reanimated";
const Stack = createNativeStackNavigator();
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "white",
},
item: {
padding: 20,
margin: 15,
backgroundColor: "whitesmoke",
},
header: {
paddingTop: 50,
padding: 15,
borderColor: "whitesmoke",
borderBottomWidth: 1,
},
headerTitle: {
fontSize: 20,
fontWeight: "bold",
},
});
function WelcomeScreen() {
const navigation = useNavigation();
const translationY = useSharedValue(0);
const scrollHandler = useAnimatedScrollHandler((event) => {
translationY.value = event.contentOffset.y;
});
const aStyle = useAnimatedStyle(() => ({
backgroundColor: interpolateColor(
translationY.value,
[0, 50],
["white", "skyblue"],
"RGB"
),
}));
React.useLayoutEffect(() => {
navigation.setOptions({
header: () => (
<Animated.View style={[styles.header, aStyle]}>
<Text style={styles.headerTitle}>Testing</Text>
</Animated.View>
),
});
}, [aStyle, navigation]);
return (
<View style={styles.container}>
<Animated.ScrollView onScroll={scrollHandler} scrollEventThrottle={16}>
{Array(15)
.fill(0)
.map((_, index) => (
<View style={styles.item} key={`${index}`}>
<Text>Item {`${index}`}</Text>
</View>
))}
</Animated.ScrollView>
<StatusBar style="auto" />
</View>
);
}
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen component={WelcomeScreen} name="Welcome" />
</Stack.Navigator>
</NavigationContainer>
);
}
Note that in this example, we're passing an Animated.View
to the header
option, passing our animated style (aStyle
) to it as a style.
Also, just like you did, I'm using useAnimatedScrollHandler
to track the scroll position, and interpolating (with interpolateColor
) the backgroundColor
of the header accordingly (between 'white' and 'skyblue', so it's easier to visualize).
Uploaded this example to this Snack so you can easily test it if you want.
I Hope this helps you solve your problem!
Error: Maximum update depth exceeded.
it is difficult to share all actual component code but the error is throwing when I use theheader
property insidesetOptions
... if I set any other property, this error is not thrown. – Cherub