import React from 'react';
import {View, StyleSheet, Platform} from 'react-native';
import {TabViewAnimated, TabViewPagerPan} from 'react-native-tab-view';
import SafeAreaView from 'react-native-safe-area-view';
import ResourceSavingSceneView from '../ResourceSavingSceneView';
import withCachedChildNavigation from '../../withCachedChildNavigation';
/**
* 基于 react-native-tab-view 的 TabViewAnimated 的 Tab 视图组件,用于 react-navigation 的 TabNavigator
*/
class TabView extends React.PureComponent {
static defaultProps = {
lazy: true,
removedClippedSubviews: true,
initialLayout: Platform.select({
android: {width: 1, height: 0},
}),
};
_handlePageChanged = index => {
const {navigation} = this.props;
navigation.navigate(navigation.state.routes[index].routeName);
};
/**
* 渲染场景组件,场景组件一般由开发人员提供,通过导航器参数 routeConfigs 设置进来
* @param route
* @return {*}
* @private
*/
_renderScene = ({route}) => {
const {screenProps, navigation} = this.props;
const focusedIndex = navigation.state.index;
const focusedKey = navigation.state.routes[focusedIndex].key;
const key = route.key;
const childNavigation = this.props.childNavigationProps[route.key];
const TabComponent = this.props.router.getComponentForRouteName(
route.routeName
);
return (
<ResourceSavingSceneView
lazy={this.props.lazy}
isFocused={focusedKey === key}
removeClippedSubViews={this.props.removeClippedSubviews}
animationEnabled={this.props.animationEnabled}
swipeEnabled={this.props.swipeEnabled}
screenProps={screenProps}
component={TabComponent}
navigation={this.props.navigation}
childNavigation={childNavigation}
/>
);
};
/**
* 获取 Tab 对应的标题
* 1. 首先尝试通过 navigationOptions.tabBarLabel function 获取;
* 2. 然后尝试通过 navigationOptions.tabBarLabel string 获取;
* 3. 然后尝试通过 navigationOptions.title string 获取;
* 3. 然后使用 routeName 作为 Tab 标题.
* @param route
* @param tintColor
* @param focused
* @return {*}
* @private
*/
_getLabel = ({route, tintColor, focused}) => {
const options = this.props.router.getScreenOptions(
this.props.childNavigationProps[route.key],
this.props.screenProps || {}
);
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;
};
/**
* 获取外部指定的 TabBar 点击回调,外部也可以不指定,
* 外部不指定的时候所使用的 tabBarComponent 组件要
* 自己处理点击事件,缺省的 tabBarComponent TabBarBottom
* 就提供了自己的点击事件处理逻辑,一般情况下都符合我们的需求
* @param previousScene
* @param route
* @return {*}
* @private
*/
_getOnPress = (previousScene, {route}) => {
const options = this.props.router.getScreenOptions(
this.props.childNavigationProps[route.key],
this.props.screenProps || {}
);
return options.tabBarOnPress;
};
_getTestIDProps = ({route, focused}) => {
const options = this.props.router.getScreenOptions(
this.props.childNavigationProps[route.key],
this.props.screenProps || {}
);
return typeof options.tabBarTestIDProps === 'function'
? options.tabBarTestIDProps({focused})
: options.tabBarTestIDProps;
};
/**
* 渲染 Tab 上的图标
* 1. 首先尝试通过 navigationOptions.tabBarIcon function 获取;
* 2. 然后尝试通过 navigationOptions.tabBarIcon 获取;
* @param focused
* @param route
* @param tintColor
* @return {*}
* @private
*/
_renderIcon = ({focused, route, tintColor}) => {
const options = this.props.router.getScreenOptions(
this.props.childNavigationProps[route.key],
this.props.screenProps || {}
);
if (options.tabBarIcon) {
return typeof options.tabBarIcon === 'function'
? options.tabBarIcon({tintColor, focused})
: options.tabBarIcon;
}
return null;
};
/**
* 渲染一个 TabBar, 主要是 Tab 上的标题,图标,以及点击回调
* 1. 获取标题 _getLabel
* 2. 渲染图标 _renderIcon
* 3. 点击回调 _getOnPress
* @param props
* @return {*}
* @private
*/
_renderTabBar = props => {
const {
tabBarOptions,
tabBarComponent: TabBarComponent,
animationEnabled,
} = this.props;
if (typeof TabBarComponent === 'undefined') {
return null;
}
return (
<TabBarComponent
{...props}
{...tabBarOptions}
tabBarPosition={this.props.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 {
router,
tabBarComponent,
tabBarPosition,
animationEnabled,
configureTransition,
initialLayout,
screenProps,
} = this.props;
let renderHeader;
let renderFooter;
let renderPager;
const {state} = this.props.navigation;
const options = router.getScreenOptions(
this.props.childNavigationProps[state.routes[state.index].key],
screenProps || {}
);
const tabBarVisible =
options.tabBarVisible == null ? true : options.tabBarVisible;
let swipeEnabled =
options.swipeEnabled == null
? this.props.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,
screenProps: this.props.screenProps,
style: styles.container,
};
return <TabViewAnimated {...props} />;
}
}
export default withCachedChildNavigation(TabView);
const styles = StyleSheet.create({
container: {
flex: 1,
},
});