UNPKG

react-native-tab-navigator

Version:

A tab bar that switches between scenes, written in JS for cross-platform support

195 lines (174 loc) 4.83 kB
'use strict'; import { Set } from 'immutable'; import React from 'react'; import PropTypes from 'prop-types'; import { StyleSheet, View, } from 'react-native'; import Badge from './Badge'; import Layout from './Layout'; import StaticContainer from './StaticContainer'; import Tab from './Tab'; import TabBar from './TabBar'; import TabNavigatorItem from './TabNavigatorItem'; import ViewPropTypes from './config/ViewPropTypes'; export default class TabNavigator extends React.Component { static propTypes = { ...ViewPropTypes, sceneStyle: ViewPropTypes.style, tabBarStyle: TabBar.propTypes.style, tabBarShadowStyle: TabBar.propTypes.shadowStyle, hidesTabTouch: PropTypes.bool }; constructor(props, context) { super(props, context); this.state = { renderedSceneKeys: this._updateRenderedSceneKeys(props.children), }; this._renderTab = this._renderTab.bind(this); } componentWillReceiveProps(nextProps) { let { renderedSceneKeys } = this.state; this.setState({ renderedSceneKeys: this._updateRenderedSceneKeys( nextProps.children, renderedSceneKeys, ), }); } _getSceneKey(item, index): string { return `scene-${(item.key !== null) ? item.key : index}`; } _updateRenderedSceneKeys(children, oldSceneKeys = Set()): Set { let newSceneKeys = Set().asMutable(); React.Children.forEach(children, (item, index) => { if (item === null) { return; } let key = this._getSceneKey(item, index); if (oldSceneKeys.has(key) || item.props.selected) { newSceneKeys.add(key); } }); return newSceneKeys.asImmutable(); } render() { let { style, children, tabBarStyle, tabBarShadowStyle, sceneStyle, ...props } = this.props; let scenes = []; React.Children.forEach(children, (item, index) => { if (item === null) { return; } let sceneKey = this._getSceneKey(item, index); if (!this.state.renderedSceneKeys.has(sceneKey)) { return; } let { selected } = item.props; let scene = <SceneContainer key={sceneKey} selected={selected} style={sceneStyle}> {item} </SceneContainer>; scenes.push(scene); }); return ( <View {...props} style={[styles.container, style]}> {scenes} <TabBar style={tabBarStyle} shadowStyle={tabBarShadowStyle}> {React.Children.map(children, this._renderTab)} </TabBar> </View> ); } _renderTab(item) { let icon; if (item === null) { return; } if (item.props.selected) { if (item.props.renderSelectedIcon) { icon = item.props.renderSelectedIcon(); } else if (item.props.renderIcon) { let defaultIcon = item.props.renderIcon(); icon = React.cloneElement(defaultIcon, { style: [defaultIcon.props.style, styles.defaultSelectedIcon], }); } } else if (item.props.renderIcon) { icon = item.props.renderIcon(); } let badge; if (item.props.renderBadge) { badge = item.props.renderBadge(); } else if (item.props.badgeText) { badge = <Badge>{item.props.badgeText}</Badge>; } return ( <Tab testID={item.props.testID} title={item.props.title} allowFontScaling={item.props.allowFontScaling} titleStyle={[ item.props.titleStyle, item.props.selected ? [ styles.defaultSelectedTitle, item.props.selectedTitleStyle, ] : null, ]} badge={badge} onPress={item.props.onPress} hidesTabTouch={this.props.hidesTabTouch} style={item.props.tabStyle}> {icon} </Tab> ); } } class SceneContainer extends React.Component { static propTypes = { ...ViewPropTypes, selected: PropTypes.bool, }; render() { let { selected, ...props } = this.props; return ( <View {...props} pointerEvents={selected ? 'auto' : 'none'} removeClippedSubviews={!selected} style={[ styles.sceneContainer, selected ? null : styles.hiddenSceneContainer, props.style, ]}> <StaticContainer shouldUpdate={selected}> {this.props.children} </StaticContainer> </View> ); } } let styles = StyleSheet.create({ container: { flex: 1, }, sceneContainer: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, paddingBottom: Layout.tabBarHeight, }, hiddenSceneContainer: { overflow: 'hidden', opacity: 0, }, defaultSelectedTitle: { color: 'rgb(0, 122, 255)', }, defaultSelectedIcon: { tintColor: 'rgb(0, 122, 255)', }, }); TabNavigator.Item = TabNavigatorItem;