mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-10 22:47:02 +08:00
Deprecate TabNavigator in favor of react-navigation-tabs
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,7 @@
|
||||
"react-lifecycles-compat": "^1.0.2",
|
||||
"react-native-drawer-layout-polyfill": "^1.3.2",
|
||||
"react-native-safe-area-view": "^0.7.0",
|
||||
"react-native-tab-view": "^0.0.74"
|
||||
"react-navigation-deprecated-tab-navigator": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
import createNavigator from './createNavigator';
|
||||
import createNavigationContainer from '../createNavigationContainer';
|
||||
import TabRouter from '../routers/TabRouter';
|
||||
import TabView from '../views/TabView/TabView';
|
||||
import TabBarTop from '../views/TabView/TabBarTop';
|
||||
import TabBarBottom from '../views/TabView/TabBarBottom';
|
||||
|
||||
const TabNavigator = (routeConfigs, config = {}) => {
|
||||
// Use the look native to the platform by default
|
||||
const tabsConfig = { ...TabNavigator.Presets.Default, ...config };
|
||||
|
||||
const router = TabRouter(routeConfigs, tabsConfig);
|
||||
|
||||
const navigator = createNavigator(TabView, router, tabsConfig);
|
||||
|
||||
return createNavigationContainer(navigator);
|
||||
};
|
||||
|
||||
const Presets = {
|
||||
iOSBottomTabs: {
|
||||
tabBarComponent: TabBarBottom,
|
||||
tabBarPosition: 'bottom',
|
||||
swipeEnabled: false,
|
||||
animationEnabled: false,
|
||||
initialLayout: undefined,
|
||||
},
|
||||
AndroidTopTabs: {
|
||||
tabBarComponent: TabBarTop,
|
||||
tabBarPosition: 'top',
|
||||
swipeEnabled: true,
|
||||
animationEnabled: true,
|
||||
initialLayout: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Use these to get Android-style top tabs even on iOS or vice versa.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* const HomeScreenTabNavigator = TabNavigator({
|
||||
* Chat: {
|
||||
* screen: ChatScreen,
|
||||
* },
|
||||
* ...
|
||||
* }, {
|
||||
* ...TabNavigator.Presets.AndroidTopTabs,
|
||||
* tabBarOptions: {
|
||||
* ...
|
||||
* },
|
||||
* });
|
||||
*```
|
||||
*/
|
||||
TabNavigator.Presets = {
|
||||
iOSBottomTabs: Presets.iOSBottomTabs,
|
||||
AndroidTopTabs: Presets.AndroidTopTabs,
|
||||
Default:
|
||||
Platform.OS === 'ios' ? Presets.iOSBottomTabs : Presets.AndroidTopTabs,
|
||||
};
|
||||
|
||||
export default TabNavigator;
|
||||
@@ -38,13 +38,17 @@ module.exports = {
|
||||
return require('./navigators/createSwitchNavigator').default;
|
||||
},
|
||||
get createTabNavigator() {
|
||||
return require('./navigators/createTabNavigator').default;
|
||||
console.warn(
|
||||
'TabNavigator is deprecated. Please use the react-navigation-tabs package instead: https://github.com/react-navigation/react-navigation-tabs'
|
||||
);
|
||||
return require('react-navigation-deprecated-tab-navigator')
|
||||
.createTabNavigator;
|
||||
},
|
||||
get TabNavigator() {
|
||||
console.warn(
|
||||
'The TabNavigator function name is deprecated, please use createTabNavigator instead'
|
||||
'TabNavigator is deprecated. Please use the react-navigation-tabs package instead: https://github.com/react-navigation/react-navigation-tabs'
|
||||
);
|
||||
return require('./navigators/createTabNavigator').default;
|
||||
return require('react-navigation-deprecated-tab-navigator').default;
|
||||
},
|
||||
get createDrawerNavigator() {
|
||||
return require('./navigators/createDrawerNavigator').default;
|
||||
@@ -80,6 +84,12 @@ module.exports = {
|
||||
get SafeAreaView() {
|
||||
return require('react-native-safe-area-view').default;
|
||||
},
|
||||
get SceneView() {
|
||||
return require('./views/SceneView').default;
|
||||
},
|
||||
get ResourceSavingSceneView() {
|
||||
return require('./views/ResourceSavingSceneView').default;
|
||||
},
|
||||
|
||||
// Header
|
||||
get Header() {
|
||||
@@ -102,13 +112,22 @@ module.exports = {
|
||||
|
||||
// TabView
|
||||
get TabView() {
|
||||
return require('./views/TabView/TabView').default;
|
||||
console.warn(
|
||||
'TabView is deprecated. Please use the react-navigation-tabs package instead: https://github.com/react-navigation/react-navigation-tabs'
|
||||
);
|
||||
return require('react-navigation-deprecated-tab-navigator').TabView;
|
||||
},
|
||||
get TabBarTop() {
|
||||
return require('./views/TabView/TabBarTop').default;
|
||||
console.warn(
|
||||
'TabBarTop is deprecated. Please use the react-navigation-tabs package instead: https://github.com/react-navigation/react-navigation-tabs'
|
||||
);
|
||||
return require('react-navigation-deprecated-tab-navigator').TabBarTop;
|
||||
},
|
||||
get TabBarBottom() {
|
||||
return require('./views/TabView/TabBarBottom').default;
|
||||
console.warn(
|
||||
'TabBarBottom is deprecated. Please use the react-navigation-tabs package instead: https://github.com/react-navigation/react-navigation-tabs'
|
||||
);
|
||||
return require('react-navigation-deprecated-tab-navigator').TabBarBottom;
|
||||
},
|
||||
|
||||
// SwitchView
|
||||
@@ -123,4 +142,7 @@ module.exports = {
|
||||
get withNavigationFocus() {
|
||||
return require('./views/withNavigationFocus').default;
|
||||
},
|
||||
get withOrientation() {
|
||||
return require('./views/withOrientation').default;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Animated,
|
||||
TouchableWithoutFeedback,
|
||||
StyleSheet,
|
||||
View,
|
||||
Platform,
|
||||
Keyboard,
|
||||
} from 'react-native';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
|
||||
import TabBarIcon from './TabBarIcon';
|
||||
import NavigationActions from '../../NavigationActions';
|
||||
import withOrientation from '../withOrientation';
|
||||
|
||||
const majorVersion = parseInt(Platform.Version, 10);
|
||||
const isIos = Platform.OS === 'ios';
|
||||
const isIOS11 = majorVersion >= 11 && isIos;
|
||||
const defaultMaxTabBarItemWidth = 125;
|
||||
|
||||
class TabBarBottom extends React.PureComponent {
|
||||
// See https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/UIKitUICatalog/UITabBar.html
|
||||
static defaultProps = {
|
||||
activeTintColor: '#3478f6', // Default active tint color in iOS 10
|
||||
activeBackgroundColor: 'transparent',
|
||||
inactiveTintColor: '#929292', // Default inactive tint color in iOS 10
|
||||
inactiveBackgroundColor: 'transparent',
|
||||
showLabel: true,
|
||||
showIcon: true,
|
||||
allowFontScaling: true,
|
||||
adaptive: isIOS11,
|
||||
};
|
||||
|
||||
_renderLabel = scene => {
|
||||
const {
|
||||
position,
|
||||
navigation,
|
||||
activeTintColor,
|
||||
inactiveTintColor,
|
||||
labelStyle,
|
||||
showLabel,
|
||||
showIcon,
|
||||
isLandscape,
|
||||
allowFontScaling,
|
||||
} = this.props;
|
||||
if (showLabel === false) {
|
||||
return null;
|
||||
}
|
||||
const { index } = scene;
|
||||
const { routes } = navigation.state;
|
||||
// Prepend '-1', so there are always at least 2 items in inputRange
|
||||
const inputRange = [-1, ...routes.map((x, i) => i)];
|
||||
const outputRange = inputRange.map(
|
||||
inputIndex => (inputIndex === index ? activeTintColor : inactiveTintColor)
|
||||
);
|
||||
const color = position.interpolate({
|
||||
inputRange,
|
||||
outputRange: outputRange,
|
||||
});
|
||||
|
||||
const tintColor = scene.focused ? activeTintColor : inactiveTintColor;
|
||||
const label = this.props.getLabel({ ...scene, tintColor });
|
||||
|
||||
if (typeof label === 'string') {
|
||||
return (
|
||||
<Animated.Text
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
styles.label,
|
||||
{ color },
|
||||
showIcon && this._shouldUseHorizontalTabs()
|
||||
? styles.labelBeside
|
||||
: styles.labelBeneath,
|
||||
labelStyle,
|
||||
]}
|
||||
allowFontScaling={allowFontScaling}
|
||||
>
|
||||
{label}
|
||||
</Animated.Text>
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof label === 'function') {
|
||||
return label({ ...scene, tintColor });
|
||||
}
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
_renderIcon = scene => {
|
||||
const {
|
||||
position,
|
||||
navigation,
|
||||
activeTintColor,
|
||||
inactiveTintColor,
|
||||
renderIcon,
|
||||
showIcon,
|
||||
showLabel,
|
||||
} = this.props;
|
||||
if (showIcon === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const horizontal = this._shouldUseHorizontalTabs();
|
||||
|
||||
return (
|
||||
<TabBarIcon
|
||||
position={position}
|
||||
navigation={navigation}
|
||||
activeTintColor={activeTintColor}
|
||||
inactiveTintColor={inactiveTintColor}
|
||||
renderIcon={renderIcon}
|
||||
scene={scene}
|
||||
style={[
|
||||
styles.iconWithExplicitHeight,
|
||||
showLabel === false && !horizontal && styles.iconWithoutLabel,
|
||||
showLabel !== false && !horizontal && styles.iconWithLabel,
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_renderTestIDProps = scene => {
|
||||
const testIDProps =
|
||||
this.props.getTestIDProps && this.props.getTestIDProps(scene);
|
||||
return testIDProps;
|
||||
};
|
||||
|
||||
_tabItemMaxWidth() {
|
||||
const { tabStyle, layout } = this.props;
|
||||
let maxTabBarItemWidth;
|
||||
|
||||
const flattenedTabStyle = StyleSheet.flatten(tabStyle);
|
||||
|
||||
if (flattenedTabStyle) {
|
||||
if (typeof flattenedTabStyle.width === 'number') {
|
||||
maxTabBarItemWidth = flattenedTabStyle.width;
|
||||
} else if (
|
||||
typeof flattenedTabStyle.width === 'string' &&
|
||||
flattenedTabStyle.endsWith('%')
|
||||
) {
|
||||
const width = parseFloat(flattenedTabStyle.width);
|
||||
if (Number.isFinite(width)) {
|
||||
maxTabBarItemWidth = layout.width * (width / 100);
|
||||
}
|
||||
} else if (typeof flattenedTabStyle.maxWidth === 'number') {
|
||||
maxTabBarItemWidth = flattenedTabStyle.maxWidth;
|
||||
} else if (
|
||||
typeof flattenedTabStyle.maxWidth === 'string' &&
|
||||
flattenedTabStyle.endsWith('%')
|
||||
) {
|
||||
const width = parseFloat(flattenedTabStyle.maxWidth);
|
||||
if (Number.isFinite(width)) {
|
||||
maxTabBarItemWidth = layout.width * (width / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!maxTabBarItemWidth) {
|
||||
maxTabBarItemWidth = defaultMaxTabBarItemWidth;
|
||||
}
|
||||
|
||||
return maxTabBarItemWidth;
|
||||
}
|
||||
|
||||
_shouldUseHorizontalTabs() {
|
||||
const { routes } = this.props.navigation.state;
|
||||
const { isLandscape, layout, adaptive, tabStyle } = this.props;
|
||||
|
||||
if (!adaptive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let tabBarWidth = layout.width;
|
||||
if (tabBarWidth === 0) {
|
||||
return Platform.isPad;
|
||||
}
|
||||
|
||||
if (!Platform.isPad) {
|
||||
return isLandscape;
|
||||
} else {
|
||||
const maxTabBarItemWidth = this._tabItemMaxWidth();
|
||||
return routes.length * maxTabBarItemWidth <= tabBarWidth;
|
||||
}
|
||||
}
|
||||
|
||||
_handleTabPress = index => {
|
||||
const { jumpToIndex, navigation } = this.props;
|
||||
const currentIndex = navigation.state.index;
|
||||
|
||||
if (currentIndex === index) {
|
||||
let childRoute = navigation.state.routes[index];
|
||||
if (childRoute.hasOwnProperty('index') && childRoute.index > 0) {
|
||||
navigation.dispatch(
|
||||
NavigationActions.popToTop({ key: childRoute.key })
|
||||
);
|
||||
} else {
|
||||
// TODO: do something to scroll to top
|
||||
}
|
||||
} else {
|
||||
jumpToIndex(index);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
position,
|
||||
navigation,
|
||||
jumpToIndex,
|
||||
getOnPress,
|
||||
getTestIDProps,
|
||||
activeBackgroundColor,
|
||||
inactiveBackgroundColor,
|
||||
style,
|
||||
animateStyle,
|
||||
tabStyle,
|
||||
isLandscape,
|
||||
} = this.props;
|
||||
const { routes } = navigation.state;
|
||||
const previousScene = routes[navigation.state.index];
|
||||
// Prepend '-1', so there are always at least 2 items in inputRange
|
||||
const inputRange = [-1, ...routes.map((x, i) => i)];
|
||||
|
||||
const tabBarStyle = [
|
||||
styles.tabBar,
|
||||
this._shouldUseHorizontalTabs() && !Platform.isPad
|
||||
? styles.tabBarCompact
|
||||
: styles.tabBarRegular,
|
||||
style,
|
||||
];
|
||||
|
||||
return (
|
||||
<Animated.View style={animateStyle}>
|
||||
<SafeAreaView
|
||||
style={tabBarStyle}
|
||||
forceInset={{ bottom: 'always', top: 'never' }}
|
||||
>
|
||||
{routes.map((route, index) => {
|
||||
const focused = index === navigation.state.index;
|
||||
const scene = { route, index, focused };
|
||||
const onPress = getOnPress(previousScene, scene);
|
||||
const outputRange = inputRange.map(
|
||||
inputIndex =>
|
||||
inputIndex === index
|
||||
? activeBackgroundColor
|
||||
: inactiveBackgroundColor
|
||||
);
|
||||
const backgroundColor = position.interpolate({
|
||||
inputRange,
|
||||
outputRange: outputRange,
|
||||
});
|
||||
|
||||
const justifyContent = this.props.showIcon ? 'flex-end' : 'center';
|
||||
const extraProps = this._renderTestIDProps(scene) || {};
|
||||
const { testID, accessibilityLabel } = extraProps;
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback
|
||||
key={route.key}
|
||||
testID={testID}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
onPress={() =>
|
||||
onPress
|
||||
? onPress({
|
||||
previousScene,
|
||||
scene,
|
||||
jumpToIndex,
|
||||
defaultHandler: this._handleTabPress,
|
||||
})
|
||||
: this._handleTabPress(index)
|
||||
}
|
||||
>
|
||||
<Animated.View style={[styles.tab, { backgroundColor }]}>
|
||||
<View
|
||||
style={[
|
||||
styles.tab,
|
||||
this._shouldUseHorizontalTabs()
|
||||
? styles.tabLandscape
|
||||
: styles.tabPortrait,
|
||||
tabStyle,
|
||||
]}
|
||||
>
|
||||
{this._renderIcon(scene)}
|
||||
{this._renderLabel(scene)}
|
||||
</View>
|
||||
</Animated.View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
})}
|
||||
</SafeAreaView>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_HEIGHT = 49;
|
||||
const COMPACT_HEIGHT = 29;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
tabBar: {
|
||||
backgroundColor: '#F7F7F7', // Default background color in iOS 10
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: 'rgba(0, 0, 0, .3)',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tabBarCompact: {
|
||||
height: COMPACT_HEIGHT,
|
||||
},
|
||||
tabBarRegular: {
|
||||
height: DEFAULT_HEIGHT,
|
||||
},
|
||||
tab: {
|
||||
flex: 1,
|
||||
alignItems: isIos ? 'center' : 'stretch',
|
||||
},
|
||||
tabPortrait: {
|
||||
justifyContent: 'flex-end',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
tabLandscape: {
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
iconWithoutLabel: {
|
||||
flex: 1,
|
||||
},
|
||||
iconWithLabel: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
iconWithExplicitHeight: {
|
||||
height: Platform.isPad ? DEFAULT_HEIGHT : COMPACT_HEIGHT,
|
||||
},
|
||||
label: {
|
||||
textAlign: 'center',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
labelBeneath: {
|
||||
fontSize: 10,
|
||||
marginBottom: 1.5,
|
||||
},
|
||||
labelBeside: {
|
||||
fontSize: 13,
|
||||
marginLeft: 20,
|
||||
},
|
||||
});
|
||||
|
||||
export default withOrientation(TabBarBottom);
|
||||
@@ -1,64 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Animated, View, StyleSheet } from 'react-native';
|
||||
|
||||
export default class TabBarIcon extends React.PureComponent {
|
||||
render() {
|
||||
const {
|
||||
position,
|
||||
scene,
|
||||
navigation,
|
||||
activeTintColor,
|
||||
inactiveTintColor,
|
||||
style,
|
||||
} = this.props;
|
||||
const { route, index } = scene;
|
||||
const { routes } = navigation.state;
|
||||
// Prepend '-1', so there are always at least 2 items in inputRange
|
||||
const inputRange = [-1, ...routes.map((x, i) => i)];
|
||||
const activeOpacity = position.interpolate({
|
||||
inputRange,
|
||||
outputRange: inputRange.map(i => (i === index ? 1 : 0)),
|
||||
});
|
||||
const inactiveOpacity = position.interpolate({
|
||||
inputRange,
|
||||
outputRange: inputRange.map(i => (i === index ? 0 : 1)),
|
||||
});
|
||||
|
||||
// We render the icon twice at the same position on top of each other:
|
||||
// active and inactive one, so we can fade between them.
|
||||
return (
|
||||
<View style={style}>
|
||||
<Animated.View style={[styles.icon, { opacity: activeOpacity }]}>
|
||||
{this.props.renderIcon({
|
||||
route,
|
||||
index,
|
||||
focused: true,
|
||||
tintColor: activeTintColor,
|
||||
})}
|
||||
</Animated.View>
|
||||
<Animated.View style={[styles.icon, { opacity: inactiveOpacity }]}>
|
||||
{this.props.renderIcon({
|
||||
route,
|
||||
index,
|
||||
focused: false,
|
||||
tintColor: inactiveTintColor,
|
||||
})}
|
||||
</Animated.View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
icon: {
|
||||
// We render the icon twice at the same position on top of each other:
|
||||
// active and inactive one, so we can fade between them:
|
||||
// Cover the whole iconContainer:
|
||||
position: 'absolute',
|
||||
alignSelf: 'center',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
},
|
||||
});
|
||||
@@ -1,135 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Animated, StyleSheet } from 'react-native';
|
||||
import { TabBar } from 'react-native-tab-view';
|
||||
import TabBarIcon from './TabBarIcon';
|
||||
|
||||
export default class TabBarTop extends React.PureComponent {
|
||||
static defaultProps = {
|
||||
activeTintColor: '#fff',
|
||||
inactiveTintColor: '#fff',
|
||||
showIcon: false,
|
||||
showLabel: true,
|
||||
upperCaseLabel: true,
|
||||
allowFontScaling: true,
|
||||
};
|
||||
|
||||
_renderLabel = scene => {
|
||||
const {
|
||||
position,
|
||||
tabBarPosition,
|
||||
navigation,
|
||||
activeTintColor,
|
||||
inactiveTintColor,
|
||||
showLabel,
|
||||
upperCaseLabel,
|
||||
labelStyle,
|
||||
allowFontScaling,
|
||||
} = this.props;
|
||||
if (showLabel === false) {
|
||||
return null;
|
||||
}
|
||||
const { index } = scene;
|
||||
const { routes } = navigation.state;
|
||||
// Prepend '-1', so there are always at least 2 items in inputRange
|
||||
const inputRange = [-1, ...routes.map((x, i) => i)];
|
||||
const outputRange = inputRange.map(
|
||||
inputIndex => (inputIndex === index ? activeTintColor : inactiveTintColor)
|
||||
);
|
||||
const color = position.interpolate({
|
||||
inputRange,
|
||||
outputRange: outputRange,
|
||||
});
|
||||
|
||||
const tintColor = scene.focused ? activeTintColor : inactiveTintColor;
|
||||
const label = this.props.getLabel({ ...scene, tintColor });
|
||||
if (typeof label === 'string') {
|
||||
return (
|
||||
<Animated.Text
|
||||
style={[styles.label, { color }, labelStyle]}
|
||||
allowFontScaling={allowFontScaling}
|
||||
>
|
||||
{upperCaseLabel ? label.toUpperCase() : label}
|
||||
</Animated.Text>
|
||||
);
|
||||
}
|
||||
if (typeof label === 'function') {
|
||||
return label({ ...scene, tintColor });
|
||||
}
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
_renderIcon = scene => {
|
||||
const {
|
||||
position,
|
||||
navigation,
|
||||
activeTintColor,
|
||||
inactiveTintColor,
|
||||
renderIcon,
|
||||
showIcon,
|
||||
iconStyle,
|
||||
} = this.props;
|
||||
if (showIcon === false) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<TabBarIcon
|
||||
position={position}
|
||||
navigation={navigation}
|
||||
activeTintColor={activeTintColor}
|
||||
inactiveTintColor={inactiveTintColor}
|
||||
renderIcon={renderIcon}
|
||||
scene={scene}
|
||||
style={[styles.icon, iconStyle]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_handleOnPress = scene => {
|
||||
const { getOnPress, jumpToIndex, navigation } = this.props;
|
||||
const previousScene = navigation.state.routes[navigation.state.index];
|
||||
const onPress = getOnPress(previousScene, scene);
|
||||
|
||||
if (onPress) {
|
||||
// To maintain the same API as `TabbarBottom`, we pass in a `defaultHandler`
|
||||
// even though I don't believe in this case it should be any different
|
||||
// than `jumpToIndex`.
|
||||
onPress({
|
||||
previousScene,
|
||||
scene,
|
||||
jumpToIndex,
|
||||
defaultHandler: jumpToIndex,
|
||||
});
|
||||
} else {
|
||||
jumpToIndex(scene.index);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
// TODO: Define full proptypes
|
||||
const props = this.props;
|
||||
|
||||
return (
|
||||
<TabBar
|
||||
{...props}
|
||||
onTabPress={this._handleOnPress}
|
||||
jumpToIndex={() => {}}
|
||||
renderIcon={this._renderIcon}
|
||||
renderLabel={this._renderLabel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
icon: {
|
||||
height: 24,
|
||||
width: 24,
|
||||
},
|
||||
label: {
|
||||
textAlign: 'center',
|
||||
fontSize: 13,
|
||||
margin: 8,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
});
|
||||
@@ -1,198 +0,0 @@
|
||||
import React from 'react';
|
||||
import { View, StyleSheet, Platform } from 'react-native';
|
||||
import { TabViewAnimated, TabViewPagerPan } from 'react-native-tab-view';
|
||||
|
||||
import ResourceSavingSceneView from '../ResourceSavingSceneView';
|
||||
|
||||
class TabView extends React.PureComponent {
|
||||
static defaultProps = {
|
||||
lazy: true,
|
||||
removedClippedSubviews: true,
|
||||
// fix for https://github.com/react-native-community/react-native-tab-view/issues/312
|
||||
initialLayout: Platform.select({
|
||||
android: { width: 1, height: 0 },
|
||||
}),
|
||||
};
|
||||
|
||||
_handlePageChanged = index => {
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate(navigation.state.routes[index].routeName);
|
||||
};
|
||||
|
||||
_renderScene = ({ route }) => {
|
||||
const { screenProps, navigation, descriptors } = this.props;
|
||||
const {
|
||||
lazy,
|
||||
removeClippedSubviews,
|
||||
animationEnabled,
|
||||
swipeEnabled,
|
||||
} = this.props.navigationConfig;
|
||||
const descriptor = descriptors[route.key];
|
||||
const focusedIndex = navigation.state.index;
|
||||
const focusedKey = navigation.state.routes[focusedIndex].key;
|
||||
const key = route.key;
|
||||
const TabComponent = descriptor.getComponent();
|
||||
return (
|
||||
<ResourceSavingSceneView
|
||||
lazy={lazy}
|
||||
isFocused={focusedKey === key}
|
||||
removeClippedSubViews={removeClippedSubviews}
|
||||
animationEnabled={animationEnabled}
|
||||
swipeEnabled={swipeEnabled}
|
||||
screenProps={screenProps}
|
||||
component={TabComponent}
|
||||
navigation={navigation}
|
||||
childNavigation={descriptor.navigation}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_getLabel = ({ route, tintColor, focused }) => {
|
||||
const { screenProps, descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = descriptor.options;
|
||||
|
||||
if (options.tabBarLabel) {
|
||||
return typeof options.tabBarLabel === 'function'
|
||||
? options.tabBarLabel({ tintColor, focused })
|
||||
: options.tabBarLabel;
|
||||
}
|
||||
|
||||
if (typeof options.title === 'string') {
|
||||
return options.title;
|
||||
}
|
||||
|
||||
return route.routeName;
|
||||
};
|
||||
|
||||
_getOnPress = (previousScene, { route }) => {
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = descriptor.options;
|
||||
|
||||
return options.tabBarOnPress;
|
||||
};
|
||||
|
||||
_getTestIDProps = ({ route }) => {
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = descriptor.options;
|
||||
|
||||
return typeof options.tabBarTestIDProps === 'function'
|
||||
? options.tabBarTestIDProps({ focused })
|
||||
: options.tabBarTestIDProps;
|
||||
};
|
||||
|
||||
_renderIcon = ({ focused, route, tintColor }) => {
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = descriptor.options;
|
||||
|
||||
if (options.tabBarIcon) {
|
||||
return typeof options.tabBarIcon === 'function'
|
||||
? options.tabBarIcon({ tintColor, focused })
|
||||
: options.tabBarIcon;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
_renderTabBar = props => {
|
||||
const {
|
||||
tabBarOptions,
|
||||
tabBarComponent: TabBarComponent,
|
||||
animationEnabled,
|
||||
tabBarPosition,
|
||||
} = this.props.navigationConfig;
|
||||
if (typeof TabBarComponent === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<TabBarComponent
|
||||
{...props}
|
||||
{...tabBarOptions}
|
||||
tabBarPosition={tabBarPosition}
|
||||
screenProps={this.props.screenProps}
|
||||
navigation={this.props.navigation}
|
||||
getLabel={this._getLabel}
|
||||
getTestIDProps={this._getTestIDProps}
|
||||
getOnPress={this._getOnPress}
|
||||
renderIcon={this._renderIcon}
|
||||
animationEnabled={animationEnabled}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_renderPager = props => <TabViewPagerPan {...props} />;
|
||||
|
||||
render() {
|
||||
const {
|
||||
tabBarComponent,
|
||||
tabBarPosition,
|
||||
animationEnabled,
|
||||
configureTransition,
|
||||
initialLayout,
|
||||
} = this.props.navigationConfig;
|
||||
|
||||
let renderHeader;
|
||||
let renderFooter;
|
||||
let renderPager;
|
||||
|
||||
const { state } = this.props.navigation;
|
||||
const route = state.routes[state.index];
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = descriptor.options;
|
||||
|
||||
const tabBarVisible =
|
||||
options.tabBarVisible == null ? true : options.tabBarVisible;
|
||||
|
||||
let swipeEnabled =
|
||||
options.swipeEnabled == null
|
||||
? this.props.navigationConfig.swipeEnabled
|
||||
: options.swipeEnabled;
|
||||
|
||||
if (typeof swipeEnabled === 'function') {
|
||||
swipeEnabled = swipeEnabled(state);
|
||||
}
|
||||
|
||||
if (tabBarComponent !== undefined && tabBarVisible) {
|
||||
if (tabBarPosition === 'bottom') {
|
||||
renderFooter = this._renderTabBar;
|
||||
} else {
|
||||
renderHeader = this._renderTabBar;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(animationEnabled === false && swipeEnabled === false) ||
|
||||
typeof configureTransition === 'function'
|
||||
) {
|
||||
renderPager = this._renderPager;
|
||||
}
|
||||
|
||||
const props = {
|
||||
initialLayout,
|
||||
animationEnabled,
|
||||
configureTransition,
|
||||
swipeEnabled,
|
||||
renderPager,
|
||||
renderHeader,
|
||||
renderFooter,
|
||||
renderScene: this._renderScene,
|
||||
onIndexChange: this._handlePageChanged,
|
||||
navigationState: this.props.navigation.state,
|
||||
style: styles.container,
|
||||
};
|
||||
|
||||
return <TabViewAnimated {...props} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default TabView;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user