diff --git a/static/assets/navigators/tabs/bottom-tabs-fade.mp4 b/static/assets/navigators/tabs/bottom-tabs-fade.mp4 new file mode 100644 index 00000000000..6e1b5a9481c Binary files /dev/null and b/static/assets/navigators/tabs/bottom-tabs-fade.mp4 differ diff --git a/static/assets/navigators/tabs/bottom-tabs-shifting.mp4 b/static/assets/navigators/tabs/bottom-tabs-shifting.mp4 new file mode 100644 index 00000000000..5ebd7a6dd61 Binary files /dev/null and b/static/assets/navigators/tabs/bottom-tabs-shifting.mp4 differ diff --git a/versioned_docs/version-7.x/bottom-tab-navigator.md b/versioned_docs/version-7.x/bottom-tab-navigator.md index b7881b371d6..5e5abea3b02 100755 --- a/versioned_docs/version-7.x/bottom-tab-navigator.md +++ b/versioned_docs/version-7.x/bottom-tab-navigator.md @@ -607,3 +607,557 @@ function MyTabs() { ); } ``` + +## Animations + +By default, switching between tabs doesn't have any animation. You can specify the `animation` option to customize the transition animation. + +Supported values for `animation` are: + +- `fade` - Cross-fade animation for the screen transition where the new screen fades in and the old screen fades out. + + + +- `shift` - Shifting animation for the screen transition where the screens slightly shift to left/right. + + + +- `none` - The screen transition doesn't have any animation. This is the default value. + + + + +```js name="Bottom Tabs animation" snack version=7 +import * as React from 'react'; +import { View, Text, Easing } from 'react-native'; +import { createStaticNavigation } from '@react-navigation/native'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +function HomeScreen() { + return ( + + Home! + + ); +} + +function ProfileScreen() { + return ( + + Profile! + + ); +} + +// codeblock-focus-start +const RootTabs = createBottomTabNavigator({ + screenOptions: { + // highlight-start + animation: 'fade', + // highlight-end + }, + screens: { + Home: HomeScreen, + Profile: ProfileScreen, + }, +}); +// codeblock-focus-end + +const Navigation = createStaticNavigation(RootTabs); + +export default function App() { + return ; +} +``` + + + + +```js name="Bottom Tabs animation" snack version=7 +import * as React from 'react'; +import { Text, View, Easing } from 'react-native'; +import { NavigationContainer } from '@react-navigation/native'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +function HomeScreen() { + return ( + + Home! + + ); +} + +function ProfileScreen() { + return ( + + Profile! + + ); +} + +const Tab = createBottomTabNavigator(); + +// codeblock-focus-start +function RootTabs() { + return ( + + + + + ); +} +// codeblock-focus-end + +export default function App() { + return ( + + + + ); +} +``` + + + + +If you need more control over the animation, you can customize individual parts of the animation using the various animation-related options: + +### Animation related options + +Bottom Tab Navigator exposes various options to configure the transition animation when switching tabs. These transition animations can be customized on a per-screen basis by specifying the options in the `options` for each screen, or for all screens in the tab navigator by specifying them in the `screenOptions`. + +- `transitionSpec` - An object that specifies the animation type (`timing` or `spring`) and its options (such as `duration` for `timing`). It contains 2 properties: + + - `animation` - The animation function to use for the animation. Supported values are `timing` and `spring`. + - `config` - The configuration object for the timing function. For `timing`, it can be `duration` and `easing`. For `spring`, it can be `stiffness`, `damping`, `mass`, `overshootClamping`, `restDisplacementThreshold` and `restSpeedThreshold`. + + A config that uses a timing animation looks like this: + + ```js + const config = { + animation: 'timing', + config: { + duration: 150, + easing: Easing.inOut(Easing.ease), + }, + }; + ``` + + We can pass this config in the `transitionSpec` option: + + + + + ```js + { + Profile: { + screen: Profile, + options: { + // highlight-start + transitionSpec: { + animation: 'timing', + config: { + duration: 150, + easing: Easing.inOut(Easing.ease), + }, + }, + // highlight-end + }, + }, + } + ``` + + + + + ```js + + ``` + + + + +- `sceneStyleInterpolator` - This is a function that specifies interpolated styles for various parts of the scene. It currently supports style for the view containing the screen: + + - `sceneStyle` - Style for the container view wrapping the screen content. + + The function receives the following properties in its argument: + + - `current` - Animation values for the current screen: + - `progress` - Animated node representing the progress value of the current screen. + + A config that fades the screen looks like this: + + ```js + const forFade = ({ current }) => ({ + sceneStyle: { + opacity: current.progress.interpolate({ + inputRange: [-1, 0, 1], + outputRange: [0, 1, 0], + }), + }, + }); + ``` + + The value of `current.progress` is as follows: + + - -1 if the index is lower than the active tab, + - 0 if they're active, + - 1 if the index is higher than the active tab + + We can pass this function in `sceneStyleInterpolator` option: + + + + + ```js + { + Profile: { + screen: Profile, + options: { + // highlight-start + sceneStyleInterpolator: ({ current }) => ({ + sceneStyle: { + opacity: current.progress.interpolate({ + inputRange: [-1, 0, 1], + outputRange: [0, 1, 0], + }), + }, + }), + // highlight-end + }, + }, + } + ``` + + + + + ```js + ({ + sceneStyle: { + opacity: current.progress.interpolate({ + inputRange: [-1, 0, 1], + outputRange: [0, 1, 0], + }), + }, + }), + // highlight-end + }} + /> + ``` + + + + +Putting these together, you can customize the transition animation for a screen: + + + + +```js name="Bottom Tabs custom animation" snack version=7 +import * as React from 'react'; +import { View, Text, Easing } from 'react-native'; +import { createStaticNavigation } from '@react-navigation/native'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +function HomeScreen() { + return ( + + Home! + + ); +} + +function ProfileScreen() { + return ( + + Profile! + + ); +} + +// codeblock-focus-start +const RootTabs = createBottomTabNavigator({ + screenOptions: { + transitionSpec: { + animation: 'timing', + config: { + duration: 150, + easing: Easing.inOut(Easing.ease), + }, + }, + sceneStyleInterpolator: ({ current }) => ({ + sceneStyle: { + opacity: current.progress.interpolate({ + inputRange: [-1, 0, 1], + outputRange: [0, 1, 0], + }), + }, + }), + }, + screens: { + Home: HomeScreen, + Profile: ProfileScreen, + }, +}); +// codeblock-focus-end + +const Navigation = createStaticNavigation(RootTabs); + +export default function App() { + return ; +} +``` + + + + +```js name="Bottom Tabs custom animation" snack version=7 +import * as React from 'react'; +import { Text, View, Easing } from 'react-native'; +import { NavigationContainer } from '@react-navigation/native'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +function HomeScreen() { + return ( + + Home! + + ); +} + +function ProfileScreen() { + return ( + + Profile! + + ); +} + +const Tab = createBottomTabNavigator(); + +// codeblock-focus-start +function RootTabs() { + return ( + ({ + sceneStyle: { + opacity: current.progress.interpolate({ + inputRange: [-1, 0, 1], + outputRange: [0, 1, 0], + }), + }, + }), + }} + > + + + + ); +} +// codeblock-focus-end + +export default function App() { + return ( + + + + ); +} +``` + + + + +### Pre-made configs + +We also export various configs from the library with ready-made configs that you can use to customize the animations: + +#### `TransitionSpecs` + +- `CrossFadeSpec` - Configuration for a cross-fade animation between screens. +- `ShiftingSpec` - Configuration for a shifting animation between screens. + +Example: + + + + +```js +import { TransitionSpecs } from '@react-navigation/bottom-tabs'; + +// ... + +{ + Profile: { + screen: Profile, + options: { + // highlight-start + transitionSpec: TransitionSpecs.CrossFadeSpec, + // highlight-end + }, + }, +} +``` + + + + +```js +import { TransitionSpecs } from '@react-navigation/bottom-tabs'; + +// ... + +; +``` + + + + +#### `SceneStyleInterpolators` + +- `forFade` - Cross-fade animation for the screen transition where the new screen fades in and the old screen fades out. +- `forShifting` - Shifting animation for the screen transition where the screens slightly shift to left/right. + +Example: + + + + +```js +import { SceneStyleInterpolators } from '@react-navigation/bottom-tabs'; + +// ... + +{ + Profile: { + screen: Profile, + options: { + // highlight-start + sceneStyleInterpolator: SceneStyleInterpolators.forFade, + // highlight-end + }, + }, +} +``` + + + + +```js +import { SceneStyleInterpolators } from '@react-navigation/bottom-tabs'; + +// ... + +; +``` + + + + +#### `TransitionPresets` + +We export transition presets that bundle various sets of these options together. A transition preset is an object containing a few animation-related screen options exported under `TransitionPresets`. Currently the following presets are available: + +- `FadeTransition` - Cross-fade animation for the screen transition where the new screen fades in and the old screen fades out. +- `ShiftingTransition` - Shifting animation for the screen transition where the screens slightly shift to left/right. + +You can spread these presets in `options` to customize the animation for a screen: + +Example: + + + + +```js +import { TransitionPresets } from '@react-navigation/bottom-tabs'; + +// ... + +{ + Profile: { + screen: Profile, + options: { + // highlight-start + ...TransitionPresets.FadeTransition, + // highlight-end + }, + }, +} +``` + + + + +```js +import { TransitionPresets } from '@react-navigation/bottom-tabs'; + +// ... + +; +``` + + +