This is probably my favorite navigation pattern on Android, I wish it were more common on iOS! This is a very simple JavaScript-only implementation of it for React Native. For more information about how the animations behind this work, check out the Rebound section of the React Native Animation Guide
- Run npm install react-native-scrollable-tab-view --save
- var ScrollableTabView = require('react-native-scrollable-tab-view');
Try out a slightly out of date version here on rnplay.org
var ScrollableTabView = require('react-native-scrollable-tab-view');
var App = React.createClass({
  render() {
    return (
      <ScrollableTabView>
        <ReactPage tabLabel="React" />
        <FlowPage tabLabel="Flow" />
        <JestPage tabLabel="Jest" />
      </ScrollableTabView>
    );
  }
}Suppose we had a custom tab bar called CustomTabBar, we would inject
it into our ScrollableTabView like this:
var ScrollableTabView = require('react-native-scrollable-tab-view');
var CustomTabBar = require('./CustomTabBar');
var App = React.createClass({
  render() {
    return (
      <ScrollableTabView renderTabBar={() => <CustomTabBar someProp={'here'} />}>
        <ReactPage tabLabel="React" />
        <FlowPage tabLabel="Flow" />
        <JestPage tabLabel="Jest" />
      </ScrollableTabView>
    );
  }
}Below is the default tab bar, renamed to CustomTabBar, you can use this as a template for implementing your own.
var React = require('react-native');
var {
  StyleSheet,
  Text,
  View,
  TouchableOpacity,
} = React;
var deviceWidth = require('Dimensions').get('window').width;
var precomputeStyle = require('precomputeStyle');
var TAB_UNDERLINE_REF = 'TAB_UNDERLINE';
var styles = StyleSheet.create({
  tab: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    paddingBottom: 10,
  },
  tabs: {
    height: 50,
    flexDirection: 'row',
    marginTop: 20,
    borderWidth: 1,
    borderTopWidth: 0,
    borderLeftWidth: 0,
    borderRightWidth: 0,
    borderBottomColor: '#ccc',
  },
});
var CustomTabBar = React.createClass({
  propTypes: {
    goToPage: React.PropTypes.func,
    activeTab: React.PropTypes.number,
    tabs: React.PropTypes.array
  },
  renderTabOption(name, page) {
    var isTabActive = this.props.activeTab === page;
    return (
      <TouchableOpacity key={name} onPress={() => this.props.goToPage(page)}>
        <View style={[styles.tab]}>
          <Text style={{color: isTabActive ? 'navy' : 'black', fontWeight: isTabActive ? 'bold' : 'normal'}}>{name}</Text>
        </View>
      </TouchableOpacity>
    );
  },
  setAnimationValue(value) {
    this.refs[TAB_UNDERLINE_REF].setNativeProps(precomputeStyle({
      left: (deviceWidth * value) / this.props.tabs.length
    }));
  },
  render() {
    var numberOfTabs = this.props.tabs.length;
    var tabUnderlineStyle = {
      position: 'absolute',
      width: deviceWidth / numberOfTabs,
      height: 4,
      backgroundColor: 'navy',
      bottom: 0,
    };
    return (
      <View style={styles.tabs}>
        {this.props.tabs.map((tab, i) => this.renderTabOption(tab, i))}
        <View style={tabUnderlineStyle} ref={TAB_UNDERLINE_REF} />
      </View>
    );
  },
});
module.exports = CustomTabBar;- renderTabBar(Function:ReactComponent) - should return a component to use as the tab bar. The component has- goToPage,- tabs,- activeTaband- refadded to the props, and should implement- setAnimationValueto be able to animate itself along with the tab content.
- onChangeTab(Function) - function to call when tab changes, should accept 1 argument which is an Object containing two keys:- i: the index of the tab that is selected,- ref: the ref of the tab that is selected
- edgeHitWidth(Integer) - region (in pixels) from the left & right edges of the screen that can trigger swipe. Default is 30, which is the same as the swipe-back gesture on iOS.
- hasTouch(Function) - returns- truewhen ScrollableTabView starts being panned and- falsewhen it is released. Not triggered when- locked(Bool) is true.
- locked(Bool) - dynamically disable scrolling between tabs.
- springTension(Integer) - a number between- 1and- 100, controls the amount of tension on the spring that guides the scroll animation - see example.
- springFriction(Integer) - a number between- 1and- 30, controls the amount of friction on the spring that guides the scroll animation - see example.
- clampSpring(Bool) - if- true, the spring will not bounce at all - if- false, it will oscillate around the target value before settling.
- children(ReactComponents) - each top-level child component should have a- tabLabelprop that can be used by the tab bar component to render out the labels. The default tab bar expects it to be a string, but you can use anything you want if you make a custom tab bar.
MIT Licensed

