|
1 | 1 | ---
|
2 |
| -id: tab-based-navigation |
3 |
| -title: Tab navigation |
4 |
| -sidebar_label: Tab navigation |
| 2 | +id: customizing-tabbar |
| 3 | +title: Customizing bottom tab bar |
| 4 | +sidebar_label: Customizing tab bar |
5 | 5 | ---
|
6 | 6 |
|
7 |
| -Possibly the most common style of navigation in mobile apps is tab-based navigation. This can be tabs on the bottom of the screen or on the top below the header (or even instead of a header). |
| 7 | +import Tabs from '@theme/Tabs'; |
| 8 | +import TabItem from '@theme/TabItem'; |
8 | 9 |
|
9 |
| -This guide covers [`createBottomTabNavigator`](bottom-tab-navigator.md). Before continuing, first install [`@react-navigation/bottom-tabs`](https://github.com/react-navigation/react-navigation/tree/main/packages/bottom-tabs): |
| 10 | +This guide covers customizing the tab bar in [`createBottomTabNavigator`](bottom-tab-navigator.md). Make sure to install and configure the library according to the [installation instructions](bottom-tab-navigator.md#installation) first. |
10 | 11 |
|
11 |
| -```bash npm2yarn |
12 |
| -npm install @react-navigation/bottom-tabs@next |
13 |
| -``` |
14 |
| - |
15 |
| -## Minimal example of tab-based navigation |
16 |
| - |
17 |
| -<Tabs groupId="config" queryString="config"> |
18 |
| -<TabItem value="static" label="Static" default> |
19 |
| - |
20 |
| -```js name="Tab based navigation" snack |
21 |
| -import * as React from 'react'; |
22 |
| -import { View, Text } from 'react-native'; |
23 |
| -import { createStaticNavigation } from '@react-navigation/native'; |
24 |
| -import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; |
25 |
| - |
26 |
| -function HomeScreen() { |
27 |
| - return ( |
28 |
| - <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> |
29 |
| - <Text>Home!</Text> |
30 |
| - </View> |
31 |
| - ); |
32 |
| -} |
33 |
| - |
34 |
| -function SettingsScreen() { |
35 |
| - return ( |
36 |
| - <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> |
37 |
| - <Text>Settings!</Text> |
38 |
| - </View> |
39 |
| - ); |
40 |
| -} |
41 |
| - |
42 |
| -const RootTabs = createBottomTabNavigator({ |
43 |
| - screens: { |
44 |
| - Home: HomeScreen, |
45 |
| - Settings: SettingsScreen, |
46 |
| - }, |
47 |
| -}); |
48 |
| - |
49 |
| -const Navigation = createStaticNavigation(RootTabs); |
50 |
| - |
51 |
| -export default function App() { |
52 |
| - return <Navigation />; |
53 |
| -} |
54 |
| -``` |
55 |
| - |
56 |
| -</TabItem> |
57 |
| -<TabItem value="dynamic" label="Dynamic"> |
58 |
| - |
59 |
| -```js name="Tab based navigation" snack |
60 |
| -import * as React from 'react'; |
61 |
| -import { Text, View } from 'react-native'; |
62 |
| -import { NavigationContainer } from '@react-navigation/native'; |
63 |
| -import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; |
64 |
| - |
65 |
| -function HomeScreen() { |
66 |
| - return ( |
67 |
| - <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> |
68 |
| - <Text>Home!</Text> |
69 |
| - </View> |
70 |
| - ); |
71 |
| -} |
72 |
| - |
73 |
| -function SettingsScreen() { |
74 |
| - return ( |
75 |
| - <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> |
76 |
| - <Text>Settings!</Text> |
77 |
| - </View> |
78 |
| - ); |
79 |
| -} |
80 |
| - |
81 |
| -const Tab = createBottomTabNavigator(); |
82 |
| - |
83 |
| -function RootTabs() { |
84 |
| - return ( |
85 |
| - <Tab.Navigator> |
86 |
| - <Tab.Screen name="Home" component={HomeScreen} /> |
87 |
| - <Tab.Screen name="Settings" component={SettingsScreen} /> |
88 |
| - </Tab.Navigator> |
89 |
| - ); |
90 |
| -} |
91 |
| - |
92 |
| -export default function App() { |
93 |
| - return ( |
94 |
| - <NavigationContainer> |
95 |
| - <RootTabs /> |
96 |
| - </NavigationContainer> |
97 |
| - ); |
98 |
| -} |
99 |
| -``` |
100 |
| - |
101 |
| -</TabItem> |
102 |
| -</Tabs> |
103 |
| - |
104 |
| - |
105 |
| - |
106 |
| -## Customizing the appearance |
| 12 | +## Add icons for each tab |
107 | 13 |
|
108 | 14 | This is similar to how you would customize a stack navigator — there are some properties that are set when you initialize the tab navigator and others that can be customized per-screen in `options`.
|
109 | 15 |
|
110 | 16 | <Tabs groupId="config" queryString="config">
|
111 | 17 | <TabItem value="static" label="Static" default>
|
112 | 18 |
|
113 |
| -```js name="Tab based navigation" snack dependencies=@expo/vector-icons,@expo/vector-icons/Ionicons |
| 19 | +```js name="Tab bar icons" snack dependencies=@expo/vector-icons,@expo/vector-icons/Ionicons |
114 | 20 | import * as React from 'react';
|
115 | 21 | import { View, Text } from 'react-native';
|
116 | 22 | import { createStaticNavigation } from '@react-navigation/native';
|
@@ -369,138 +275,16 @@ export default function App() {
|
369 | 275 |
|
370 | 276 | From UI perspective this component is ready to use, but you still need to find some way to pass down the badge count properly from somewhere else, like using [React Context](https://reactjs.org/docs/context.html), [Redux](https://redux.js.org/), [MobX](https://mobx.js.org/) or [event emitters](https://github.com/facebook/react-native/blob/master/Libraries/vendor/emitter/EventEmitter.js).
|
371 | 277 |
|
372 |
| - |
373 |
| - |
374 |
| -## Jumping between tabs |
375 |
| - |
376 |
| -Switching from one tab to another has a familiar API — `navigation.navigate`. |
377 |
| - |
378 |
| -<samp id="tab-based-navigation-switching" /> |
379 |
| - |
380 |
| -```js |
381 |
| -function HomeScreen() { |
382 |
| - const navigation = useNavigation(); |
383 |
| - |
384 |
| - return ( |
385 |
| - <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> |
386 |
| - <Text>Home!</Text> |
387 |
| - <Button onPress={() => navigation.navigate('Settings')}> |
388 |
| - Go to Settings |
389 |
| - </Button> |
390 |
| - </View> |
391 |
| - ); |
392 |
| -} |
393 |
| - |
394 |
| -function SettingsScreen() { |
395 |
| - const navigation = useNavigation(); |
396 |
| - |
397 |
| - return ( |
398 |
| - <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> |
399 |
| - <Text>Settings!</Text> |
400 |
| - <Button onPress={() => navigation.navigate('Home')}>Go to Home</Button> |
401 |
| - </View> |
402 |
| - ); |
403 |
| -} |
404 |
| -``` |
405 |
| - |
406 |
| -<video playsInline autoPlay muted loop> |
407 |
| - <source src="/assets/navigators/tabs/tabs-navigate.mp4" /> |
408 |
| -</video> |
409 |
| - |
410 |
| -## A stack navigator for each tab |
411 |
| - |
412 |
| -Often tabs don't just display one screen — for example, on your Twitter feed, you can tap on a tweet and it brings you to a new screen within that tab with all of the replies. You can think of this as there being separate navigation stacks within each tab, and that's exactly how we will model it in React Navigation. |
413 |
| - |
414 |
| -<samp id="tab-based-navigation-stack" /> |
| 278 | +You can also update the badge from within the screen component by using the `setOptions` method: |
415 | 279 |
|
416 | 280 | ```js
|
417 |
| -import * as React from 'react'; |
418 |
| -import { Text, View } from 'react-native'; |
419 |
| -import { NavigationContainer, useNavigation } from '@react-navigation/native'; |
420 |
| -import { createNativeStackNavigator } from '@react-navigation/native-stack'; |
421 |
| -import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; |
422 |
| -import { Button } from '@react-navigation/elements'; |
423 |
| - |
424 |
| -function DetailsScreen() { |
425 |
| - return ( |
426 |
| - <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> |
427 |
| - <Text>Details!</Text> |
428 |
| - </View> |
429 |
| - ); |
430 |
| -} |
431 |
| - |
432 |
| -function HomeScreen() { |
433 |
| - const navigation = useNavigation(); |
434 |
| - |
435 |
| - return ( |
436 |
| - <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> |
437 |
| - <Text>Home screen</Text> |
438 |
| - <Button onPress={() => navigation.navigate('Details')}> |
439 |
| - Go to Details |
440 |
| - </Button> |
441 |
| - </View> |
442 |
| - ); |
443 |
| -} |
444 |
| - |
445 |
| -function SettingsScreen() { |
446 |
| - const navigation = useNavigation(); |
447 |
| - |
448 |
| - return ( |
449 |
| - <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> |
450 |
| - <Text>Settings screen</Text> |
451 |
| - <Button onPress={() => navigation.navigate('Details')}> |
452 |
| - Go to Details |
453 |
| - </Button> |
454 |
| - </View> |
455 |
| - ); |
456 |
| -} |
457 |
| - |
458 |
| -const HomeStack = createNativeStackNavigator(); |
459 |
| - |
460 |
| -function HomeStackScreen() { |
461 |
| - return ( |
462 |
| - <HomeStack.Navigator> |
463 |
| - <HomeStack.Screen name="Home" component={HomeScreen} /> |
464 |
| - <HomeStack.Screen name="Details" component={DetailsScreen} /> |
465 |
| - </HomeStack.Navigator> |
466 |
| - ); |
467 |
| -} |
468 |
| - |
469 |
| -const SettingsStack = createNativeStackNavigator(); |
| 281 | +const navigation = useNavigation(); |
470 | 282 |
|
471 |
| -function SettingsStackScreen() { |
472 |
| - return ( |
473 |
| - <SettingsStack.Navigator> |
474 |
| - <SettingsStack.Screen name="Settings" component={SettingsScreen} /> |
475 |
| - <SettingsStack.Screen name="Details" component={DetailsScreen} /> |
476 |
| - </SettingsStack.Navigator> |
477 |
| - ); |
478 |
| -} |
479 |
| - |
480 |
| -const Tab = createBottomTabNavigator(); |
481 |
| - |
482 |
| -export default function App() { |
483 |
| - return ( |
484 |
| - <NavigationContainer> |
485 |
| - <Tab.Navigator screenOptions={{ headerShown: false }}> |
486 |
| - <Tab.Screen name="HomeStack" component={HomeStackScreen} /> |
487 |
| - <Tab.Screen name="SettingsStack" component={SettingsStackScreen} /> |
488 |
| - </Tab.Navigator> |
489 |
| - </NavigationContainer> |
490 |
| - ); |
491 |
| -} |
| 283 | +React.useEffect(() => { |
| 284 | + navigation.setOptions({ |
| 285 | + tabBarBadge: unreadMessagesCount, |
| 286 | + }); |
| 287 | +}, [navigation, unreadMessagesCount]); |
492 | 288 | ```
|
493 | 289 |
|
494 |
| -<video playsInline autoPlay muted loop> |
495 |
| - <source src="/assets/navigators/tabs/tabs-with-stack.mp4" /> |
496 |
| -</video> |
497 |
| - |
498 |
| -## Why do we need a TabNavigator instead of TabBarIOS or some other component? |
499 |
| - |
500 |
| -It's common to attempt to use a standalone tab bar component without integrating it into the navigation library you use in your app. In some cases, this works fine! You should be warned, however, that you may run into some frustrating unanticipated issues when doing this. |
501 |
| - |
502 |
| -For example, React Navigation's tab navigator takes care of handling the Android back button for you, while standalone components typically do not. Additionally, it is more difficult for you (as the developer) to perform actions such as "jump to this tab and then go to this screen" if you need to call into two distinct APIs for it. Lastly, mobile user interfaces have numerous small design details that require that certain components are aware of the layout or presence of other components — for example, if you have a translucent tab bar, content should scroll underneath it and the scroll view should have an inset on the bottom equal to the height of the tab bar so you can see all of the content. Double tapping the tab bar should make the active navigation stack pop to the top of the stack, and doing it again should scroll the active scroll view in that stack scroll to the top. While not all of these behaviors are implemented out of the box yet with React Navigation, they will be and you will not get any of this if you use a standalone tab view component. |
503 |
| - |
504 |
| -## A tab navigator contains a stack and you want to hide the tab bar on specific screens |
505 |
| - |
506 |
| -[See the documentation here](hiding-tabbar-in-screens.md) |
| 290 | + |
0 commit comments