react-native-reanimated
react-native-reanimated copied to clipboard
Incompatibility with React Navigation Native Stack: causes content to be placed under the app bar on Android
Description
When using layout animations in a tabbed/stack view combination using react-navigation's NativeStack (a fairly common use case), once an animation occurs it will cause the content on top of the screen to be hidden behind the app bar on Android.
All tabs that weren't open before the animation occurred, once opened, will also show this behavior.
Expected behavior
The content should not be hidden by the app bar
Actual behavior & steps to reproduce
Once the layout animation occurs, the app bar on the native stack navigator where the animation is will hide the top of the content. Any tab that has not been opened before the animation occurred, when opened, will show the same issue.
tapping animated tab first and then "other tab"
opening "other tab" first and then animated tab

Snack or minimal code example
The relevant code is this:
import 'react-native-gesture-handler';
import * as React from 'react';
import {StyleSheet, Text, View} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import Animated, {BounceIn, BounceOut} from 'react-native-reanimated';
const styles = StyleSheet.create({
bigText: {
fontSize: 30,
},
});
function NormalScreen() {
return (
<View>
<Text style={styles.bigText}>This is a screen without animation.</Text>
</View>
);
}
function AnimatedScreen() {
return (
<View>
<Animated.Text
entering={BounceIn}
exiting={BounceOut}
style={styles.bigText}>
{`Screen with layout animation. Opening this screen will move the content below the app bar.
If this tab is viewed before the "OtherTab", switching to that tab will also show its content under the app bar.
If "OtherTab" is opened first, then only this tab will have the issue.
Once the issue happens, only restarting the app returns it to normal.
`}
</Animated.Text>
</View>
);
}
const HomeStack = createNativeStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={NormalScreen} />
</HomeStack.Navigator>
);
}
const AnotherTabStack = createNativeStackNavigator();
function AnotherTabStackScreen() {
return (
<AnotherTabStack.Navigator>
<AnotherTabStack.Screen name="Another" component={NormalScreen} />
</AnotherTabStack.Navigator>
);
}
const AnimatedTabStack = createNativeStackNavigator();
function AnimatedTabStackScreen() {
return (
<AnimatedTabStack.Navigator>
<AnimatedTabStack.Screen name="Animated" component={AnimatedScreen} />
</AnimatedTabStack.Navigator>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator screenOptions={{headerShown: false}}>
<Tab.Screen name="HomeTab" component={HomeStackScreen} />
<Tab.Screen name="AnimatedTab" component={AnimatedTabStackScreen} />
<Tab.Screen name="OtherTab" component={AnotherTabStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
Package versions
| name | version |
|---|---|
| react-native | 0.69.1 |
| react-native-reanimated | ^2.9.1 |
| @react-navigation/stack | ^6.2.2 |
| @react-navigation/native-stack | ^6.7.0 |
| @react-navigation/native | ^6.0.11 |
| @react-navigation/bottom-tabs | ^6.3.2 |
Affected platforms
- [ x ] Android
- [ ] iOS
- [ ] Web
this is caused by the layout animation.
this is caused by the layout animation.
That is correct. Once the entering/exiting animations are removed the issue stops occurring.
this is caused by the layout animation.
That is correct. Once the entering/exiting animations are removed the issue stops occurring.
yes, the layout animation makes component doesn't unmount correctly
Its currently undergoing a rewrite, might be fixed soon
Yeah, facing a similar issue. Using it in the header
Yep same here, if we add <Animated.View layout={CurvedTransition}> within a screen then the header overlaps the children of the screen
I don't even need layout prop. Just adding Animated.View on the screen causes the issue.
It gets worse when using ScrollView and TextInput together. (flickering)

export default function NotFoundScreen({ navigation }: RootStackScreenProps<'NotFound'>) {
return (
<ScrollView contentContainerStyle={styles.container}>
<Text style={styles.title}>Title 1</Text>
<Text style={styles.title}>Title 2</Text>
<Text style={styles.title}>Title 3</Text>
<Text style={styles.title}>Title 4</Text>
<Text style={styles.title}>Title 5</Text>
<Animated.View>
<Image source={require('../assets/images/favicon.png')} />
</Animated.View>
<TextInput style={styles.input} />
<TouchableOpacity onPress={() => navigation.push('NotFound')} style={styles.link}>
<Text style={styles.linkText}>Next screen!</Text>
</TouchableOpacity>
</ScrollView>
);
}
I don't even need
layoutprop. Just addingAnimated.Viewon the screen causes the issue. It gets worse when usingScrollViewandTextInputtogether. (flickering)export default function NotFoundScreen({ navigation }: RootStackScreenProps<'NotFound'>) { return ( <ScrollView contentContainerStyle={styles.container}> <Text style={styles.title}>Title 1</Text> <Text style={styles.title}>Title 2</Text> <Text style={styles.title}>Title 3</Text> <Text style={styles.title}>Title 4</Text> <Text style={styles.title}>Title 5</Text> <Animated.View> <Image source={require('../assets/images/favicon.png')} /> </Animated.View> <TextInput style={styles.input} /> <TouchableOpacity onPress={() => navigation.push('NotFound')} style={styles.link}> <Text style={styles.linkText}>Next screen!</Text> </TouchableOpacity> </ScrollView> ); }
facing the same issue right now, don't have any LayoutAnimation and the component didn't unmount
We're also running into this issue. We have an entering and exiting animation and as soon as it runs once, all screens that have a tabbed header within the stack overlap their content. On iOS, the library works FANTASTIC, but this is unfortunately a blocker for our Android implementation.
Seeing this too
The same issue here. Animated.View component does nothing wrong, but as soon as I include entering or exiting prop the header covers the top content of the screen.
surprisingly this only happens with NativeStack headers and not with things linke BottomNavigation headers
/cc @satya164 I'm not sure if this is an issue in reanimated or with NativeStack. What do you think?
This bug was very difficult to figure out 🐒 Trying to refactor out Moti and finding out that it would break the navigation header by doing:
import * as Reanimated from 'react-native-reanimated'
...
<Reanimated.default.View entering={Reanimated.FadeIn}>
@hirbod is there any status on this?
I'm having the same issue here.
Will this be fixed soon? The library is unusable right now.
@piaskowyk cool thanks for fixing this!