reanimated-tab-view
v1.1.0
Published
Tab view component implemented using Reanimated 4
Readme
Reanimated Tab View
A custom Tab View component implemented using react-native-reanimated and react-native-gesture-handler. Props are almost entirely inter-compatible with react-native-tab-view
For Docs → https://adithyavis.github.io/reanimated-tab-view/
⚠️ IMPORTANT: This README and the docs linked above cover reanimated-tab-view 1.x, which is built on Reanimated 4 and therefore runs on the New Architecture only. If you are still on Reanimated 3, use the 0.x release line instead — its source lives on the
v0.xbranch, and its documentation is at 0.x docs (also reachable from the version dropdown on the docs site).
Demo
| Instagram | Basic | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | | |
The example/ folder contains reference code for these examples and also is a good place to learn how to use the library.
Motivation
- The original react-native-tab-view is an amazing package, no doubt. However,
it is dependent on
react-native-pager-view. This dependency complicates solving issues such as
TabView tab index not really controlledTab label aligning vertically in some devices when render single tab.Screen getting stuck when switching between the tabs while keyboard opened..
reanimated-tab-view depends purely on react-native-reanimated, and as such, the above issues won't be encountered.
I wanted swipe and jump-to behaviors. My implementation of the swipe and jump-to behaviors are built from scratch using the animation and gesture primitives offered by react-native-reanimated and react-native-gesture-handler.
I wanted collapsible headers in the original react-native-tab-view, however they didn't provide support. Many real apps like Instagram, X, Reddit and LinkedIn have tab views in their apps that support collapsible headers. I consider it an anti-pattern for a tab view component to not have support for collapsible headers.
Features
You can also refer to https://adithyavis.github.io/reanimated-tab-view/docs/features.
reanimated-tab-view provides the following features that are provided by react-native-tab-view
- Smooth animations and gestures
- Scrollable tabs
- Supports both top and bottom tab bars
- Follows Material Design spec
- Highly customizable
- Fully typed with TypeScript
Additionally, reanimated-tab-view also provides the following features
Collapsible headers
Currently supported on ios and android
Works with
RTVScrollView,RTVFlatList,RTVFlashList(FlashList) andRTVLegendList(Legend List)
3 render modes to render the tab view ("all", "windowed" and "lazy"). Can be modified using the
renderModeprop.- All render mode renders all the scenes in one go, during the initial tab view mount. When the number of scenes is large, it is recommended to use the window mode/lazy mode. This is the default render mode.
- Windowed render mode renders a window of scenes, including the current scene and the scenes adjascent to it. It is recommended to use this render mode when the number of scenes is large but when the render cost of each scene is not high.
- Lazy render mode renders the scenes one by one when they are first mounted to the view. It is recommended to use this render mode when the number of scenes is large and when the render cost of each scene is high.
Dynamic widths for tabs, based on the tab title length. For eg., if the tab title is "Tab one", the width of the tab will be smaller than if the tab title is "Tab hundred one". Can be modified using the
tabBarDynamicWidthEnabledprop.This feature is in accordance with the Material Design spec.
By default, this feature is enabled when the
tabBarTypeprop is set to'primary'.
Customisable jump-to animations (smooth jump or scroll jump). Can be modified using the
jumpModeprop.Scrolling jump: When jumped from tab one to tab four, the jump animation scrolls through the scenes in between (scenes of tab two and tab three). In case the scenes in between haven't been already rendered (while using lazy/windowed render modes), the jump-to animation will result in a momentary blank splash.
Smooth jump: When jumped from tab one to tab four, the jump animation smoothly animates to the target scene of tab four without scrolling through the scenes in between. This helps prevent blank splashes when using lazy/windowed render modes. This is enabled by default.
No animation: When jumped from tab one to tab four, the jump animation does not animate to the target scene of tab four. This is useful when you want to jump to a scene without any animation.
| Smooth Jump | Scroll Jump | | :----------------------------------------------: | :----------------------------------------------: | | | |
Installation
You can also refer to https://adithyavis.github.io/reanimated-tab-view/docs/installation.
Install react-native-reanimated (>=4.x), react-native-worklets (>=0.4.x) and react-native-gesture-handler (>=2.x). Reanimated 4 runs on the New Architecture only, so your app must have it enabled.
- https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started
- https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation
Open a Terminal in the project root and run:
yarn add reanimated-tab-viewOptional peer dependencies
Only needed if you render the matching component inside a scene. Leaving them out is fine.
| Package | Version | Needed for |
| -------------------------------------------------------------- | -------- | --------------- |
| @shopify/flash-list | >= 2.0.0 | RTVFlashList |
| @legendapp/list | >= 3.0.0 | RTVLegendList |
Quick Start
You can also refer to https://adithyavis.github.io/reanimated-tab-view/docs/quick-start.
import * as React from 'react';
import { View, useWindowDimensions } from 'react-native';
import { TabView } from 'reanimated-tab-view';
const FirstRoute = () => (
<View style={{ flex: 1, backgroundColor: '#ff4081' }} />
);
const SecondRoute = () => (
<View style={{ flex: 1, backgroundColor: '#673ab7' }} />
);
const renderScene = ({ route }) => {
switch (route.key) {
case 'first':
return <FirstRoute />;
case 'second':
return <SecondRoute />;
default:
return null;
}
};
export default function TabViewExample() {
const layout = useWindowDimensions();
const [index, setIndex] = React.useState(0);
const [routes] = React.useState([
{ key: 'first', title: 'First' },
{ key: 'second', title: 'Second' },
]);
return (
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={{ tabView: { width: layout.width } }}
/>
);
}