A cross-platform Tab View component for React Native.
This is a JavaScript-only implementation of swipeable tab views. It's super customizable, allowing you to do things like coverflow.
- Run the example app to see it in action.
- Checkout the example/ folder for source code.
- Smooth animations and gestures
- Scrollable tabs
- Both top and bottom tab bars
- Follows Material Design spec
- Highly customizable
npm install --save react-native-tab-view react-addons-shallow-compareimport React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import { TabViewAnimated, TabBarTop } from 'react-native-tab-view';
const styles = StyleSheet.create({
container: {
flex: 1,
},
page: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export default class TabViewExample extends Component {
state = {
index: 0,
routes: [
{ key: '1', title: 'First' },
{ key: '2', title: 'Second' },
],
};
_handleChangeTab = (index) => {
this.setState({ index });
};
_renderHeader = (props) => {
return <TabBarTop {...props} />;
};
_renderScene = ({ route }) => {
switch (route.key) {
case '1':
return <View style={[ styles.page, { backgroundColor: '#ff4081' } ]} />;
case '2':
return <View style={[ styles.page, { backgroundColor: '#673ab7' } ]} />;
default:
return null;
}
};
render() {
return (
<TabViewAnimated
style={styles.container}
navigationState={this.state}
renderScene={this._renderScene}
renderHeader={this._renderHeader}
onRequestChangeTab={this._handleChangeTab}
/>
);
}
}The package exposes the following components,
Container component responsible for managing tab transitions
It accepts the following props,
navigationState- the current navigation stateconfigureTransition- optional callback which returns a configuration for the transition, returnnullto disable animationonRequestChangeTab- callback for when the current tab changes, should do thesetStateonChangePosition- callback called with position value as it changes (e.g. - on swipe or tab change), avoid doing anything expensive herecanJumpToTab- optional callback which accepts a route, and returns a boolean indicating whether jumping to the tab is allowedinitialLayout- optional object containing the initialheightandwidth, can be passed to prevent the one frame delay in renderingshouldOptimizeUpdates- whether to implement ashouldComponentUpdatestrategy to minimize updates, enabled by defaultrender- callback which renders the tab view, gets a special set of props as argument
A convenience wrapper around <TabViewTransitioner />
It accepts the following props in addition to all the props accepted by <TabViewTransitioner /> (except render),
renderPager- optional callback which renders a pager responsible for handling swipesrenderHeader- optional callback which renders a header, useful for a top tab barrenderFooter- optional callback which renders a footer, useful for a bottom tab barrenderScene- callback which renders a single scenelazy- whether to load tabs lazily when you start switching
Pager component based on PanResponder (default)
It accepts the following props,
swipeEnabled- whether to enable swipe gesturesswipeDistanceThreshold- minimum swipe distance to trigger page switchswipeVelocityThreshold- minimum swipe velocity to trigger page switchchildren- React Element(s) to render
Pager component based on ScrollView
It accepts the following props,
swipeEnabled- whether to enable swipe gestureschildren- React Element(s) to render
Pager component based on ViewPagerAndroid
It accepts the following props,
swipeEnabled- whether to enable swipe gestureschildren- React Element(s) to render
Basic tab bar
It accepts the following props,
renderIcon- optional callback which receives the current scene and returns a React Element to be used as a iconrenderLabel- optional callback which receives the current scene and returns a React Element to be used as a labelrenderIndicator- optional callback which receives the current scene and returns a React Element to be used as a tab indicatorrenderBadge- optional callback which receives the current scene and returns a React Element to be used as a badgeonTabPress- optional callback invoked on tab press, useful for things like scroll to toppressColor- color for material ripple (Android >= 5.0 only)activeOpacity- opacity for pressed tab (iOS and Android < 5.0 only)scrollEnabled- whether to enable scrollable tabstabWidth- optional custom tab width for scrollable tabstabStyle- style object for the tab
Material design themed top tab bar
It accepts the following props in addition to the props accepted by <TabBar />,
renderLabel- optional callback which receives the current scene and returns a React Element to be used as a labelindicatorStyle- style object for the tab indicatorlabelStyle- style object for the tab label
Check the type definitions for details on shape of different objects.
<TabViewAnimated /> and <TabViewTransitioner /> implement shouldComponentUpdate to prevent unnecessary re-rendering. As a side-effect, the tabs won't re-render if something changes in the parent's state. If you need it to trigger a re-render, put it in the navigationState.
For example, consider you have a loaded property on state which should trigger re-render. You can have your state like the following -
state = {
index: 0,
routes: [
{ key: '1', title: 'First' },
{ key: '2', title: 'Second' },
],
loaded: false,
}Then pass this.state as the navigationState prop to <TabViewAnimated /> or <TabViewTransitioner />.
<TabViewAnimated
navigationState={this.state}
renderScene={this._renderPage}
renderHeader={this._renderHeader}
onRequestChangeTab={this._handleChangeTab}
/>-
The
renderScenefunction is called every time the index changes. If yourrenderScenefunction is expensive, it's good idea move it to a separate component if yourrenderScenefunction doesn't depend on the index, and applyshouldComponentUpdateto prevent unnecessary re-renders. -
If you've a large number of routes, especially images, it can slow the animation down a lot. You can instead render a limited number of routes. In your
renderScenefunction, do the following to render only 2 routes on each side,renderScene = ({ route }) => { if (Math.abs(this.state.navigation.index - this.state.navigation.routes.indexOf(route)) > 2) { return null; } return <MySceneComponent route={route} />; };
zIndex in React Native is buggy which results in weird behaviour when you remove adjacent items from the hierarchy. You can try setting zIndex to 0 for the TabBar to avoid the issue.
