1 | # Native Stack Navigator
|
2 |
|
3 | Provides a way for your app to transition between screens where each new screen is placed on top of a stack.
|
4 |
|
5 | By default the stack navigator is configured to have the familiar iOS and Android look & feel: new screens slide in from the right on iOS, fade in from the bottom on Android. On iOS, the stack navigator can also be configured to a modal style where screens slide in from the bottom.
|
6 |
|
7 | This navigator uses native navigation primitives (`UINavigationController` on iOS and `Fragment` on Android) for navigation under the hood. The main difference from React Navigation's JS-based [stack navigator](https://reactnavigation.org/docs/stack-navigator.html) is that the JS-based navigator re-implements animations and gestures while the native stack navigator relies on the platform primitives for animations and gestures. You should use this navigator if you want native feeling and performance for navigation and don't need much customization, as the customization options of this navigator are limited.
|
8 |
|
9 | ```sh
|
10 | npm install react-native-screens @react-navigation/native
|
11 | ```
|
12 |
|
13 | ## Disabling `react-native-screens`
|
14 |
|
15 | If, for whatever reason, you'd like to disable native screens support and use plain React Native Views add the following code in your entry file (e.g. `App.js`):
|
16 |
|
17 | ```js
|
18 | import { enableScreens } from 'react-native-screens';
|
19 |
|
20 | enableScreens(false);
|
21 | ```
|
22 |
|
23 | ## API Definition
|
24 |
|
25 | To use this navigator, import it from `react-native-screens/createNativeStackNavigator`:
|
26 |
|
27 | ```js
|
28 | import createNativeStackNavigator from 'react-native-screens/createNativeStackNavigator';
|
29 |
|
30 | const RootStack = createNativeStackNavigator(
|
31 | {
|
32 | Home: HomeScreen,
|
33 | Details: DetailsScreen,
|
34 | },
|
35 | {
|
36 | initialRouteName: 'Home',
|
37 | }
|
38 | );
|
39 | ```
|
40 |
|
41 | ### StackNavigatorConfig
|
42 |
|
43 | Visual options:
|
44 |
|
45 | - `mode` - it is an option from `stackNavigator` and controls the stack presentation along with `cardTransparent` prop. Use `stackPresentation` instead to be consistent with v5 `native-stack`. Available options are: `'modal'`, `'containedModal'`.
|
46 | - `headerMode` - it is an option from `stackNavigator` and it hides the header when set to `none`. Use `headerShown` instead to be consistent with v5 `native-stack`. Available option is: `'none'`.
|
47 | - `transparentCard` - This is a boolean from `stackNavigator` that controls the stack presentation along with `mode` prop. Use `stackPresentation` instead to be consistent with v5 `native-stack`.
|
48 |
|
49 | ### `navigationOptions` for screens inside of the navigator
|
50 |
|
51 | Options from `stack` navigator:
|
52 |
|
53 | - `header` - makes the header hide when set to `null`. Use `headerShown` instead to be consistent with v5 `native-stack`.
|
54 | - `cardTransparent` - boolean that controls the stack presentation along with `mode` prop. Use `stackPresentation` instead to be consistent with v5 `native-stack`.
|
55 | - `animationEnabled`- boolean that sets stack animation to none when `false` passed. Use `stackAnimation: 'none'` instead to be consistent with v5 `native-stack`.
|
56 | - `cardStyle` - style prop for `Screen` component.
|
57 |
|
58 | Options for back button taken from `react-navigation-stack`:
|
59 |
|
60 | - `headerBackImage` - maps to [`headerBackImage`](https://reactnavigation.org/docs/4.x/stack-navigator#headerbackimage)
|
61 | - `headerPressColorAndroid` - maps to [`headerPressColorAndroid`](https://reactnavigation.org/docs/4.x/stack-navigator#headerpresscolorandroid)
|
62 | - `headerTintColor` - maps to [`headerTintColor`](https://reactnavigation.org/docs/4.x/stack-navigator#headertintcolor)
|
63 | - `backButtonTitle` - maps to [`headerBackTitle`](https://reactnavigation.org/docs/4.x/stack-navigator#headerbacktitle)
|
64 | - `truncatedBackButtonTitle` - maps to [`headerTruncatedBackTitle`](https://reactnavigation.org/docs/4.x/stack-navigator#headertruncatedbacktitle)
|
65 | - `backTitleVisible` - maps to [`headerBackTitleVisible`](https://reactnavigation.org/docs/4.x/stack-navigator#headerbacktitlevisible)
|
66 | - `headerBackTitleStyle` - maps to [`headerBackTitleStyle`](https://reactnavigation.org/docs/4.x/stack-navigator#headerbacktitlestyle)
|
67 | - `layoutPreset` - Layout of the title element in the header.
|
68 |
|
69 | Legacy options (these props differ from the ones used in v5 `native-stack`, and we would like to keep the API consistent between versions):
|
70 |
|
71 | - `hideShadow` - see `headerHideShadow`.
|
72 | - `largeTitle` - see `headerLargeTitle`.
|
73 | - `largeTitleHideShadow` - see `headerLargeTitleHideShadow`.
|
74 | - `translucent` - see `headerTranslucent`.
|
75 |
|
76 | #### `backButtonInCustomView`
|
77 |
|
78 | Boolean indicating whether to hide the back button while using `headerLeft` function.
|
79 |
|
80 | #### `customAnimationOnSwipe` (iOS only)
|
81 |
|
82 | Boolean indicating that swipe dismissal should trigger animation provided by `stackAnimation`. Defaults to `false`.
|
83 |
|
84 | #### `direction`
|
85 |
|
86 | String that applies `rtl` or `ltr` form to the stack. On Android, you have to add `android:supportsRtl="true"` in the manifest of your app to enable `rtl`. On Android, if you set the above flag in the manifest, the orientation changes without the need to do it programmatically if the phone has `rtl` direction enabled. On iOS, the direction defaults to `ltr`, and only way to change it is via this prop.
|
87 |
|
88 | #### `disableBackButtonMenu` (iOS only)
|
89 |
|
90 | Boolean indicating whether to show the menu on longPress of iOS >= 14 back button.
|
91 |
|
92 | #### `fullScreenSwipeEnabled` (iOS only)
|
93 |
|
94 | Boolean indicating whether the swipe gesture should work on whole screen. Swiping with this option results in the same transition animation as `simple_push` by default. It can be changed to other custom animations with `customAnimationOnSwipe` prop, but default iOS swipe animation is not achievable due to usage of custom recognizer. Defaults to `false`.
|
95 |
|
96 | #### `gestureEnabled` (iOS only)
|
97 |
|
98 | Whether you can use gestures to dismiss this screen. Defaults to `true`.
|
99 |
|
100 | #### `headerBackTitle`
|
101 |
|
102 | Title string used by the back button on iOS. Defaults to the previous scene's `headerTitle`.
|
103 |
|
104 | #### `headerBackTitleStyle`
|
105 |
|
106 | Style object for header back title. Supported properties:
|
107 |
|
108 | - `fontFamily`
|
109 | - `fontSize`
|
110 |
|
111 | #### `headerBackTitleVisible` (iOS only)
|
112 |
|
113 | Whether the back button title should be visible or not. Defaults to `true`.
|
114 |
|
115 | #### `headerHideBackButton`
|
116 |
|
117 | Boolean indicating whether to hide the back button in the header.
|
118 |
|
119 | #### `headerHideShadow`
|
120 |
|
121 | Boolean indicating whether to hide the elevation shadow on the header.
|
122 |
|
123 | #### `headerLargeStyle` (iOS only)
|
124 |
|
125 | Style object for the large header. Supported properties:
|
126 |
|
127 | - `backgroundColor`
|
128 |
|
129 | #### `headerLargeTitle` (iOS only)
|
130 |
|
131 | Boolean used to set a native property to prefer a large title header (like in iOS setting).
|
132 |
|
133 | For the large title to collapse on scroll, the content of the screen should be wrapped in a scrollable view such as `ScrollView` or `FlatList`. If the scrollable area doesn't fill the screen, the large title won't collapse on scroll.
|
134 |
|
135 | #### `headerLargeTitleHideShadow` (iOS only)
|
136 |
|
137 | Boolean that allows for disabling drop shadow under navigation header when the edge of any scrollable content reaches the matching edge of the navigation bar.
|
138 |
|
139 | #### `headerLargeTitleStyle` (iOS only)
|
140 |
|
141 | Style object for header large title. Supported properties:
|
142 |
|
143 | - `color`
|
144 | - `fontFamily`
|
145 | - `fontSize`
|
146 | - `fontWeight`
|
147 |
|
148 | #### `headerLeft`
|
149 |
|
150 | Function which returns a React Element to display on the left side of the header. For now, on Android, using it will cause the title to also disappear.
|
151 |
|
152 | #### `headerRight`
|
153 |
|
154 | Function which returns a React Element to display on the right side of the header.
|
155 |
|
156 | #### `headerShown`
|
157 |
|
158 | Whether to show or hide the header for the screen. The header is shown by default. Setting this to `false` hides the header.
|
159 |
|
160 | #### `headerStyle`
|
161 |
|
162 | Style object for the header. Supported properties:
|
163 |
|
164 | - `backgroundColor`
|
165 | - `blurEffect` (iOS only).
|
166 |
|
167 | #### `headerTintColor`
|
168 |
|
169 | Tint color for the header. Changes the color of the back button and title.
|
170 |
|
171 | #### `headerTitle`
|
172 |
|
173 | String to be used by the header as title string. Defaults to scene `title`.
|
174 |
|
175 | #### `headerTitleStyle`
|
176 |
|
177 | Style object for header title. Supported properties:
|
178 |
|
179 | - `fontFamily`
|
180 | - `fontSize`
|
181 | - `fontWeight`
|
182 | - `color`
|
183 |
|
184 | #### `headerTopInsetEnabled` (Android only)
|
185 |
|
186 | A Boolean to that lets you opt out of insetting the header. You may want to * set this to `false` if you use an opaque status bar. Defaults to `true`. Insets are always applied on iOS because the header cannot be opaque.
|
187 |
|
188 | #### `headerTranslucent`
|
189 |
|
190 | Boolean indicating whether the navigation bar is translucent.
|
191 |
|
192 | #### `nativeBackButtonDismissalEnabled` (Android only)
|
193 |
|
194 | Boolean indicating whether, when the Android default back button is clicked, the `pop` action should be performed on the native side or on the JS side to be able to prevent it.
|
195 | Unfortunately the same behavior is not available on iOS since the behavior of native back button cannot be changed there.
|
196 |
|
197 | Defaults to `false`.
|
198 |
|
199 | #### `replaceAnimation`
|
200 |
|
201 | How should the screen replacing another screen animate.
|
202 | The following values are currently supported:
|
203 | - `push` – the new screen will perform push animation.
|
204 | - `pop` – the new screen will perform pop animation.
|
205 |
|
206 | Defaults to `pop`.
|
207 |
|
208 | #### `stackAnimation`
|
209 |
|
210 | How the given screen should appear/disappear when pushed or popped at the top of the stack. Possible values:
|
211 |
|
212 | - `default` - Uses a platform default animation.
|
213 | - `fade` - Fades screen in or out.
|
214 | - `fade_from_bottom` – performs a fade from bottom animation
|
215 | - `flip` – Flips the screen, requires stackPresentation: `modal` (iOS only).
|
216 | - `simple_push` – performs a default animation, but without shadow and native header transition (iOS only)
|
217 | - `slide_from_bottom` – performs a slide from bottom animation
|
218 | - `slide_from_right` - slide in the new screen from right to left (Android only, resolves to default transition on iOS)
|
219 | - `slide_from_left` - slide in the new screen from left to right (Android only, resolves to default transition on iOS)
|
220 | - `none` - The screen appears/disappears without an animation.
|
221 |
|
222 | Defaults to `default`.
|
223 |
|
224 | #### `stackPresentation`
|
225 |
|
226 | How the screen should be presented. Possible values:
|
227 |
|
228 | - `push` - The new screen will be pushed onto a stack. The default animation on iOS is to slide from the side. The animation on Android may vary depending on the OS version and theme.
|
229 | - `modal` - The new screen will be presented modally. In addition, this allows for a nested stack to be rendered inside such screens.
|
230 | - `transparentModal` - The new screen will be presented modally. In addition, the second to last screen will remain attached to the stack container such that if the top screen is translucent, the content below can still be seen. If `"modal"` is used instead, the below screen gets removed as soon as the transition ends.
|
231 | - `containedModal` – will use "UIModalPresentationCurrentContext" modal style on iOS and will fallback to `"modal"` on Android.
|
232 | - `containedTransparentModal` – will use "UIModalPresentationOverCurrentContext" modal style on iOS and will fallback to `"transparentModal"` on Android.
|
233 | - `fullScreenModal` – will use "UIModalPresentationFullScreen" modal style on iOS and will fallback to `"modal"` on Android.
|
234 | - `formSheet` – will use "UIModalPresentationFormSheet" modal style on iOS and will fallback to `"modal"` on Android.
|
235 |
|
236 | Defaults to `push`.
|
237 |
|
238 | Using `containedModal` and `containedTransparentModal` with other types of modals in one native stack navigator is not recommended and can result in a freeze or a crash of the application.
|
239 |
|
240 | #### `title`
|
241 |
|
242 | A string that can be used as a fallback for `headerTitle`.
|
243 |
|
244 | #### `useTransitionProgress`
|
245 |
|
246 | Hook providing context value of transition progress of the current screen to be used with `react-native` `Animated`. It consists of 2 values:
|
247 | - `progress` - `Animated.Value` between `0.0` and `1.0` with the progress of the current transition.
|
248 | - `closing` - `Animated.Value` of `1` or `0` indicating if the current screen is being navigated into or from.
|
249 | - `goingForward` - `Animated.Value` of `1` or `0` indicating if the current transition is pushing or removing screens.
|
250 |
|
251 | ```jsx
|
252 | import {Animated} from 'react-native';
|
253 | import {useTransitionProgress} from 'react-native-screens';
|
254 |
|
255 | function Home() {
|
256 | const {progress} = useTransitionProgress();
|
257 |
|
258 | const opacity = progress.interpolate({
|
259 | inputRange: [0, 0.5, 1],
|
260 | outputRange: [1.0, 0.0 ,1.0],
|
261 | extrapolate: 'clamp',
|
262 | });
|
263 |
|
264 | return (
|
265 | <Animated.View style={{opacity, height: 50, width: '100%', backgroundColor: 'green'}} />
|
266 | );
|
267 | }
|
268 | ```
|
269 |
|
270 | #### `useReanimatedTransitionProgress`
|
271 |
|
272 | A callback called every frame during the transition of screens to be used with `react-native-reanimated` version `2.x`. It consists of 2 shared values:
|
273 | - `progress` - between `0.0` and `1.0` with the progress of the current transition.
|
274 | - `closing` - `1` or `0` indicating if the current screen is being navigated into or from.
|
275 | - `goingForward` - `1` or `0` indicating if the current transition is pushing or removing screens.
|
276 |
|
277 | In order to use it, you need to have `react-native-reanimated` version `2.x` installed in your project and wrap your code with `ReanimatedScreenProvider`, like this:
|
278 |
|
279 | ```jsx
|
280 | import {ReanimatedScreenProvider} from 'react-native-screens/reanimated';
|
281 |
|
282 | export default function App() {
|
283 | return (
|
284 | <ReanimatedScreenProvider>
|
285 | <YourApp />
|
286 | </ReanimatedScreenProvider>
|
287 | );
|
288 | }
|
289 | ```
|
290 |
|
291 | Then you can use `useReanimatedTransitionProgress` to get the shared values:
|
292 |
|
293 | ```jsx
|
294 | import {useReanimatedTransitionProgress} from 'react-native-screens/reanimated';
|
295 | import Animated, {useAnimatedStyle, useDerivedValue} from 'react-native-reanimated';
|
296 |
|
297 | function Home() {
|
298 | const reaProgress = useReanimatedTransitionProgress();
|
299 | const sv = useDerivedValue(() => (reaProgress.progress.value < 0.5 ? (reaProgress.progress.value * 50) : ((1 - reaProgress.progress.value) * 50)) + 50);
|
300 | const reaStyle = useAnimatedStyle(() => {
|
301 | return {
|
302 | width: sv.value,
|
303 | height: sv.value,
|
304 | backgroundColor: 'blue',
|
305 | };
|
306 | });
|
307 |
|
308 | return (
|
309 | <Animated.View style={reaStyle} />
|
310 | );
|
311 | }
|
312 | ```
|
313 |
|
314 | ### Status bar and orientation managment
|
315 |
|
316 | With `native-stack`, the status bar and screen orientation can be managed by `UIViewController` on iOS. On Android, the status bar and screen orientation can be managed by `FragmentActivity`. On iOS, it requires:
|
317 |
|
318 | 1. For status bar managment: enabling (or deleting) `View controller-based status bar appearance` in your Info.plist file (it disables the option to use React Native's `StatusBar` component).
|
319 | 2. For both status bar and orientation managment: adding `#import <RNScreens/UIViewController+RNScreens.h>` in your project's `AppDelegate.m` (you can see this change applied in the `AppDelegate.m` of `Example` project).
|
320 |
|
321 | On Android, no additional setup is required, although, you should keep in mind that once you set the orientation or status bar props, `react-native-screens` will manage them on every screen, so you shouldn't use other methods of manipulating them then.
|
322 | #### `screenOrientation`
|
323 |
|
324 | Sets the current screen's available orientations and forces rotation if current orientation is not included. On iOS, if you have supported orientations set in `info.plist`, they will take precedence over this prop. Possible values:
|
325 |
|
326 | - `default` - on iOS, it resolves to [UIInterfaceOrientationMaskAllButUpsideDown](https://developer.apple.com/documentation/uikit/uiinterfaceorientationmask/uiinterfaceorientationmaskallbutupsidedown?language=objc). On Android, this lets the system decide the best orientation.
|
327 | - `all`
|
328 | - `portrait`
|
329 | - `portrait_up`
|
330 | - `portrait_down`
|
331 | - `landscape`
|
332 | - `landscape_left`
|
333 | - `landscape_right`
|
334 |
|
335 | Defaults to `default`.
|
336 |
|
337 | #### `statusBarAnimation`
|
338 |
|
339 | Sets the status bar animation (similar to the `StatusBar` component). Possible values: `fade`, `none`, `slide`. On Android, this prop considers the transition of changing status bar color (see https://reactnative.dev/docs/statusbar#animated). There will be no animation if `none` provided.
|
340 |
|
341 | Defaults to `fade` on iOS and `none` on Android.
|
342 |
|
343 | #### `statusBarColor` (Android only)
|
344 |
|
345 | Sets the status bar color (similar to the `StatusBar` component). Defaults to initial status bar color.
|
346 |
|
347 | #### `statusBarHidden`
|
348 |
|
349 | Boolean saying if the status bar for this screen is hidden.
|
350 |
|
351 | Defaults to `false`.
|
352 |
|
353 | #### `statusBarStyle`
|
354 |
|
355 | Sets the status bar color (similar to the `StatusBar` component). On iOS, the possible values are: `auto` (based on [user interface style](https://developer.apple.com/documentation/uikit/uiuserinterfacestyle?language=objc), `inverted` (colors opposite to `auto`), `light`, `dark`. On Android, the status bar will be dark if set to `dark` and `light` otherwise.
|
356 |
|
357 | Defaults to `auto`.
|
358 |
|
359 | #### `statusBarTranslucent` (Android only)
|
360 |
|
361 | Sets the translucency of the status bar (similar to the `StatusBar` component). Defaults to `false`.
|
362 |
|
363 | ### Search bar (iOS only)
|
364 |
|
365 | The search bar is just a `searchBar` property that can be specified in the navigator's `defaultNavigationOptions` prop or an individual screen's `navigationOptions`. Search bars are rarely static so normally it is controlled by passing an object to `searchBar` navigation option in the component's body.
|
366 |
|
367 | Search bar is only supported on iOS.
|
368 |
|
369 | Example:
|
370 |
|
371 | ```js
|
372 | static navigationOptions = ({navigation}) => {
|
373 | return {
|
374 | searchBar: {
|
375 | // search bar options
|
376 | },
|
377 | };
|
378 | };
|
379 | ```
|
380 |
|
381 | Supported properties are described below.
|
382 |
|
383 | #### `autoCapitalize`
|
384 |
|
385 | Controls whether the text is automatically auto-capitalized as it is entered by the user.
|
386 | Possible values:
|
387 |
|
388 | - `none`
|
389 | - `words`
|
390 | - `sentences`
|
391 | - `characters`
|
392 |
|
393 | Defaults to `sentences`.
|
394 |
|
395 | #### `barTintColor`
|
396 |
|
397 | The search field background color.
|
398 |
|
399 | By default bar tint color is translucent.
|
400 |
|
401 | #### `cancelButtonText`
|
402 |
|
403 | The text to be used instead of default `Cancel` button text.
|
404 |
|
405 | #### `hideNavigationBar`
|
406 |
|
407 | Boolean indicating whether to hide the navigation bar during searching.
|
408 |
|
409 | Defaults to `true`.
|
410 |
|
411 | #### `hideWhenScrolling`
|
412 |
|
413 | Boolean indicating whether to hide the search bar when scrolling.
|
414 |
|
415 | Defaults to `true`.
|
416 |
|
417 | #### `obscureBackground`
|
418 |
|
419 | Boolean indicating whether to obscure the underlying content with semi-transparent overlay.
|
420 |
|
421 | Defaults to `true`.
|
422 |
|
423 | #### `onBlur`
|
424 |
|
425 | A callback that gets called when search bar has lost focus.
|
426 |
|
427 | #### `onCancelButtonPress`
|
428 |
|
429 | A callback that gets called when the cancel button is pressed.
|
430 |
|
431 | #### `onChangeText`
|
432 |
|
433 | A callback that gets called when the text changes. It receives the current text value of the search bar.
|
434 |
|
435 | Example:
|
436 |
|
437 | ```js
|
438 | static navigationOptions = ({navigation}) => {
|
439 | return {
|
440 | searchBar: {
|
441 | onChangeText: (event) => {
|
442 | navigation.setParams({search: event.nativeEvent.text});
|
443 | },
|
444 | },
|
445 | };
|
446 | };
|
447 | ```
|
448 |
|
449 | #### `onFocus`
|
450 |
|
451 | A callback that gets called when search bar has received focus.
|
452 |
|
453 | #### `onSearchButtonPress`
|
454 |
|
455 | A callback that gets called when the search button is pressed. It receives the current text value of the search bar.
|
456 |
|
457 | #### `placeholder`
|
458 |
|
459 | Text displayed when search field is empty.
|
460 |
|
461 | Defaults to an empty string.
|
462 |
|
463 | #### `textColor`
|
464 |
|
465 | The search field text color.
|
466 |
|
467 | #### `hintTextColor`
|
468 |
|
469 | The search hint text color. (Android only)
|
470 |
|
471 | #### `headerIconColor`
|
472 |
|
473 | The search and close icon color shown in the header. (Android only)
|
474 |
|
475 | #### `shouldShowHintSearchIcon`
|
476 |
|
477 | Show the search hint icon when search bar is focused. (Android only)
|
478 |
|
479 | ### Helpers
|
480 |
|
481 | The stack navigator adds the following methods to the navigation prop:
|
482 |
|
483 | #### `push`
|
484 |
|
485 | Pushes a new screen to the top of the stack and navigate to it. The method accepts the following arguments:
|
486 |
|
487 | - `name` - _string_ - Name of the route to push onto the stack.
|
488 | - `params` - _object_ - Screen params to merge into the destination route (found in the pushed screen through `route.params`).
|
489 |
|
490 | ```js
|
491 | navigation.push('Profile', { name: 'Wojtek' });
|
492 | ```
|
493 |
|
494 | #### `pop`
|
495 |
|
496 | Pops the current screen from the stack and navigates back to the previous screen. It takes one optional argument (`count`), which allows you to specify how many screens to pop back by.
|
497 |
|
498 | ```js
|
499 | navigation.pop();
|
500 | ```
|
501 |
|
502 | #### `popToTop`
|
503 |
|
504 | Pops all of the screens in the stack except the first one and navigates to it.
|
505 |
|
506 | ```js
|
507 | navigation.popToTop();
|
508 | ```
|
509 |
|
510 | ## Additional options
|
511 |
|
512 | ### Measuring header's height
|
513 |
|
514 | To measure header's height, you can use `useHeaderHeight` hook.
|
515 |
|
516 | ```tsx
|
517 | import {useHeaderHeight} from 'react-native-screens/native-stack';
|
518 | ```
|