Changing navigation animation direction in react-native? - react-native

I'm currently working on a mobile application written in react-native.
This project has a number of different screens all of which are configured with createStackNavigator.
I need to be able to change the animation direction on the fly. I could be navigating to the same page on different parts of the app but require different animations. (by animation I means the direction the current screen exits the view)
I am aware options can be passed to the screen when defined to set the navigation direction. This is unfortunately no use to me as the animation may change from page to page.
Example screen declaration from my project (names have been sanitised):
<NavigationContainer ref={navigationRef}>
<Stack.Navigator initialRouteName={initialRoute}>
<Stack.Screen name="screen1" component={screen1} options={{headerShown: false, gestureEnabled: false}} />
<Stack.Screen name="screen2" component={screen2} options={{headerShown: false, gestureEnabled: false}} />
<Stack.Screen name="screen3" component={screen3} options={{headerShown: false, gestureEnabled: false}} />
<Stack.Screen name="screen4" component={screen4} options={{headerShown: false, gestureEnabled: false}} />
</Stack.Navigator>
</NavigationContainer>
Example navigation reset:
navigation.reset({
index: 0,
routes: [{ name: "screen1", params: { param1: 'paramStrData' } }]
});
Example navigation replace:
navigation.replace('screen2', { param1: 'param1StrData'})
Ideally, I'd like to be able to pass a navigation animation direction to the replace or reset functions.
Is this at all possible?
Thanks again in advance.

add props persentation , animationTypeForReplace , animation like this.
<Stack.Screen
name="screen1"
component={screen1}
options={{
headerShown: false,
presentation: 'modal',
animationTypeForReplace: 'push',
animation:'slide_from_right'
}}
/>

Pass animation,presentation and animationTypeForReplace props inside options
example.
<Stack.Screen
name="screen"
component={screen}
options={{
headerShown: false,
presentation: 'modal',
animationTypeForReplace: 'push',
animation:'slide_from_right'
}}
/>

Both answers above contributed to a solution in some way.
My understanding of the navigation stack was a little flawed at this time.
We can't dynamically change the animation type - i.e. swipe left or right.
The animation type is selected based on where the new screen is on the navigation stack or not. If already on the stack, the current screen will exit to the right and the new (previous) screen will enter from the left - this is to simulate going back.
If the new screen is not on the navigation stack, the new screen will enter from the right to simulate adding a new screen to the navigation stack.
naviagation.navigate('screenName', {param1: 'p1', param2: 'p2'})
navigate needs to be used opposed to replace to make this work.
Hope this helps someone at some point as this was something I struggled to understand for some time.

Related

Structure for nested navigation with react-native-navigation

I am currently building my first app using react-native and i am struggeling with the right structure for nested navigation using react-native-navigation .
My app should be navigatable using a Tab-bar. On every screen of that Tab-bar I might need to have a Stack navigation available.
App.js:
<NavigatonContainer>
<BottomTab.Navigator>
<BottomTab.Screen name="Screen1" component={Screen1}/>
<BottomTab.Screen name="Screen2" component={Screen2}/>
<BottomTab.Screen name="Screen3" component={Screen3}/>
<BottomTab.Navigator/>
<NavigationContainer/>
Now if i want to use a Stack navigation inside Screen1, what would be the best approach? My approach would be to move all content that should be display when the first Tab is active to a new screen called "Screen1Start" and then having following code on "Screen1".
Screen1.js:
<Stack.Navigator>
<Stack.Screen name="Screen1Start" component={Screen1Start}/>
<Stack.Screen name="Screen1Settings" component={Screen1Settings}/>
<Stack.Screen name="Screen1Details" component={Screen1Details}/>
</Stack.Navigator>
Is that the right thing to do? Are there better approaches to this? Thanks for your help!
You can have a stack inside of a stack and then navigate to each individually with navigation.navigate('name'). In the react navigation docs you can read more about navigating inside nested navigators here.
Pretty quick example would be:
function Home() {
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="Messages" component={Messages} />
</Tab.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
</NavigationContainer>
);
}
Here you can see that Home is a stack of feed and messages and then you have individual screens for Profile and Settings. Like so you can have another stack instead of Profile or Settings binded by another navigator such as toptab or bottomtab.
The react navigation docs explain this very detailed and easy to understand. I would recommend you to read from start to finish so you have a deeper understanding of the navigation.

How to push modal in react-navigation

i want to push multiples times the same modal, but when i run navigation.push, the modal is not a modal.
It's possible to use navigation.push to show a modal ?
UPDATE:
I have set the animationEnabled to false, so modal didn’t work
You can have modals in navigation stacks. For the screens to show up as modal, they need to be configured as such. So where you create your navigation stack, add presentation: "modal" to the screenOptions.
From the documentation:
function RootStackScreen() {
return (
<RootStack.Navigator>
<RootStack.Group>
<RootStack.Screen name="Home" component={HomeScreen} />
<RootStack.Screen name="Details" component={DetailsScreen} />
</RootStack.Group>
<RootStack.Group screenOptions={{ presentation: 'modal' }}>
<RootStack.Screen name="MyModal" component={ModalScreen} />
</RootStack.Group>
</RootStack.Navigator>
);
}
If you have multiple screens configured as modal, you should be able to push them above each other.

Render one component over another at a certain route with react-navigation

I have a stack navigator with react router, using #react-navigation/native-stack. My home screen is a map, and I have a few menu components:
export const App = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
options={{ headerShown: false }}
component={Home}
/>
<Stack.Screen
name="SignIn"
component={SignIn}
/>
</Stack.Navigator>
</NavigationContainer>
)
}
Home is the map component, and SignIn, as well as some other components, are menu components that take over the screen when navigated to, pushing Home out of the way, as expected.
I want to be able to 'navigate' to another component at a certain route, call it Overlay. When routed here, I want to show the home screen, with an Overlay component laid over the top of part of the Home component, while still maintaining interactivity with the part of the Home screen that is not covered. However, if I do this:
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
options={{ headerShown: false }}
component={Home}
/>
<Stack.Screen
name="Overlay"
component={Overlay}
/>
</Stack.Navigator>
Then the Home screen moves away, and is replaced by Overlay.
How can I show a component overlaid over the top of my Home screen when the user is routed to a certain route? This is something easily done with react-router, but I'm not sure if there is a parallel in react-navigation. Is react-navigation not the right approach for this? Is it better to conditionally render the Overlay component based on a state/redux variable?

React-native going back from a nested navigation container does not work

I am creating a nested navigation container in react-native and the stack looks like this:
-Main Navigation Container:
- Home
- Market Navigation Container:
- Market
- Cart
- About
When I go to home or about and go back, it works properly. However, when I go back from Market or cart (Which I expect to go to the Home page) it shows an error saying:
The action 'POP' with payload {"count":1} was not handled by any navigator.
Is there any screen to go back to?
This is a development-only warning and won't be shown in production.
This is my code for the main navigation container:
<NavigationContainer independent={true}>
<Stack.Navigator>
<Stack.Screen options={myOptions} name="Home" component={Home} />
<Stack.Screen
options={{ headerShown: false }}
name="MarketNavigation"
component={MarketNavigation}
/>
<Stack.Screen options={myOptions} name="About" component={About} />
</Stack.Navigator>
</NavigationContainer>
And this is my code for the market navigation:
<NavigationContainer ref={navigationRef} independent={true}>
<Stack.Navigator>
<Stack.Screen
options={myOptions}
name="Market"
component={Market}
/>
<Stack.Screen
options={myOptions}
name="Cart"
component={Cart}
/>
</Stack.Navigator>
</NavigationContainer>
I faced this when navigating to nested navigator using "screen" option like this:
navigation.navigate('Root', {
screen: 'Settings'
})
;
As mentioned in the documentation:
By default, when you navigate a screen in the nested navigator, the
specified screen is used as the initial screen and the initial route
prop on the navigator is ignored.
To solve this you should use "initial: false" like so:
navigation.navigate('Root', {
screen: 'Settings',
initial: false,
});
Could you add in the code where you navigate from Home to MarketNavigation and back?

Stack.Navigator fade-transition between Stack.Screens in React-native?

How can I add a transition effect to Stacked Screes in React-native?
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Stocks" component={StocksScreen} />
</Stack.Navigator>
</NavigationContainer>
Is there a default way to achieve a fadeIn / fadeOut effect?
The simplest way to achieve fade effect:
const forFade = ({ current }) => ({
cardStyle: {
opacity: current.progress,
},
});
If you want to apply fade effect for the entire navigator:
<Stack.Navigator
screenOptions={{
headerShown: false,
cardStyleInterpolator: forFade,
}}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Stocks" component={StocksScreen} />
</Stack.Navigator>
Also you can apply cardStyleInterpolator for single screen via setting options:
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ cardStyleInterpolator: forFade }}/>
You can customize forFade function in order to achieve other effects, or also you can use some pre-made interpolators, as:
forHorizontalIOS
forVerticalIOS
forModalPresentationIOS
forFadeFromBottomAndroid
forRevealFromBottomAndroid
import { CardStyleInterpolators } from '#react-navigation/stack';
<Stack.Screen
name="Profile"
component={Profile}
options={{
cardStyleInterpolator: CardStyleInterpolators.forFadeFromBottomAndroid,
}}
/>;
More info here: https://reactnavigation.org/docs/stack-navigator/#animations
For React Navigation 6.xx you can use the animation option:
<Stack.Screen
name="Profile"
component={Profile}
options={{ animation: 'fade' }}
/>
Supported values:
"default": use the platform default animation
"fade": fade screen in or out
"flip": flip the screen, requires presentation: "modal" (iOS only)
"simple_push": use the platform default animation, but without shadow and native header transition (iOS only)
"slide_from_bottom": slide in the new screen from bottom
"slide_from_right": slide in the new screen from right (Android only, uses default animation on iOS)
"slide_from_left": slide in the new screen from left (Android only, uses default animation on iOS)
"none": don't animate the screen