首先看下效果
react-navigation是不支持自定义背景的,但产品有需求没办法。只能扩展喽~~ 注意那棵小树的处理,高度是透出来的,并且整个背景是在page之上的!只有后面两个按钮可在页面中进行单击,滑动跳转。单击游戏,则退出此业务模块。
修改如下:
1.node_modules/react-navigation/src/views/TabView/TabView.js
在外面将背景图和style传参进来,在_renderTabBar方法中实现渲染背景图,并根据传参是否支持背景图,红色部分为主要修改位置, 请注意_renderTabBar()方法的修改
/* @flow */
import * as React from 'react';
import {
Image,
Text,
} from 'react-native';
import {View, StyleSheet, Platform} from 'react-native';
import {TabViewAnimated, TabViewPagerPan} from 'react-native-tab-view';
import type {Layout} from 'react-native-tab-view/src/TabViewTypeDefinitions';
import SceneView from '../SceneView';
import withCachedChildNavigation from '../../withCachedChildNavigation';
import SafeAreaView from '../SafeAreaView';
import type {
NavigationScreenProp,
NavigationRoute,
NavigationState,
NavigationRouter,
NavigationTabScreenOptions,
} from '../../TypeDefinition';
export
type
TabViewConfig = {
tabBarComponent? : React.ComponentType < * >,
tabBarPosition? : 'top' | 'bottom',
tabBarOptions? : {},
swipeEnabled? : boolean,
animationEnabled? : boolean,
configureTransition? : (currentTransitionProps: Object,
nextTransitionProps: Object) => Object,
lazy? : boolean,
initialLayout? : Layout,
};
export
type
TabScene = {
route: NavigationRoute,
focused: boolean,
index: number,
tintColor? : ? string,
};
type
Props = {
tabBarComponent? : React.ComponentType < * >,
tabBarPosition? : 'top' | 'bottom',
tabBarOptions? : {},
swipeEnabled? : boolean,
animationEnabled? : boolean,
configureTransition? : (currentTransitionProps: Object,
nextTransitionProps: Object) => Object,
lazy? : boolean,
initialLayout: Layout,
screenProps? : {},
navigation: NavigationScreenProp < NavigationState >,
router: NavigationRouter < NavigationState, NavigationTabScreenOptions >,
childNavigationProps
:
{
[key
:
string
]:
NavigationScreenProp < NavigationRoute >,
}
,
}
;
class TabView extends React.PureComponent {
static defaultProps = {
// fix for https://github.com/react-native-community/react-native-tab-view/issues/312
initialLayout: Platform.select({
android: {width: 1, height: 0},
}),
};
_handlePageChanged = (index: number) => {
const {navigation, onPageChange} = this.props;
onPageChange(index, this.props.screenProps);
navigation.navigate(navigation.state.routes[index].routeName);
};
_renderScene = ({route}: any) => {
const {screenProps} = this.props;
const childNavigation = this.props.childNavigationProps[route.key];
const TabComponent = this.props.router.getComponentForRouteName(
route.routeName
);
return (
);
};
_getLabel = ({route, tintColor, focused}: TabScene) => {
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;
};
_getOnPress = (previousScene: TabScene, {route}: TabScene) => {
const options = this.props.router.getScreenOptions(
this.props.childNavigationProps[route.key],
this.props.screenProps || {}
);
return options.tabBarOnPress;
};
_getTestIDProps = ({route}: TabScene) => {
const options = this.props.router.getScreenOptions(
this.props.childNavigationProps[route.key],
this.props.screenProps || {}
);
return options.tabBarTestIDProps;
};
_renderIcon = ({focused, route, tintColor}: TabScene) => {
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;
};
_renderTabBar = (props: *) => {
const {
tabBarOptions,
tabBarComponent: TabBarComponent,
animationEnabled,
} = this.props;
if (typeof TabBarComponent === 'undefined') {
return null;
}
const bgImgOptions = tabBarOptions.bgImgOptions;
const marginTopValue = bgImgOptions && bgImgOptions.showBgImg ? bgImgOptions.marginTop : 0;
return (
{this._renderBgImg(bgImgOptions)}
);
};
_renderBgImg(bgImgOptions) {
if (bgImgOptions && bgImgOptions.showBgImg) {
const widthValue = bgImgOptions.width;
const heightValue = bgImgOptions.height;
return (
);
}
}
_renderPager = (props: *) => ;
render() {
const {
router,
tabBarComponent,
tabBarPosition,
animationEnabled,
configureTransition,
swipeEnabled,
lazy,
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;
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 = {
lazy,
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,
};
// $FlowFixMe: mismatch with react-native-tab-view type
return ;
}
}
export default withCachedChildNavigation(TabView);
const styles = StyleSheet.create({
container: {
flex: 1,
},
page: {
flex: 1,
overflow: 'hidden',
backgroundColor: 'transparent',
},
});
2.如果有需求,第一个按钮直接返回到主界面,相对来说,当前模块只是一个子业务模块的时候,我们可以改变下面TabBottom的布局,android和iOS的平台不一致,如有需要只改变:
npde_modules/react-native-tab-view/TabBar.js 插入红色的部分,此为render方法中return实现// android平台下面的tabBar的实现
return (
{this._renderIndicator({
...this.props,
width: new Animated.Value(finalTabWidth),
})}
{this.props.gameButton}
{routes.map((route, i) => {
const focused = index === i;
const outputRange = inputRange.map(
inputIndex => (inputIndex === i ? 1 : 0.7)
);
const opacity = Animated.multiply(
this.state.visibility,
position.interpolate({
inputRange,
outputRange,
})
);
const scene = {
route,
focused,
index: i,
};
const label = this._renderLabel(scene);
const icon = this.props.renderIcon
? this.props.renderIcon(scene)
: null;
const badge = this.props.renderBadge
? this.props.renderBadge(scene)
: null;
const tabStyle = {};
tabStyle.opacity = opacity;
if (icon) {
if (label) {
tabStyle.paddingTop = 8;
} else {
tabStyle.padding = 12;
}
}
const passedTabStyle = StyleSheet.flatten(this.props.tabStyle);
const isWidthSet =
(passedTabStyle &&
typeof passedTabStyle.width !== 'undefined') ||
scrollEnabled === true;
const tabContainerStyle = {};
if (isWidthSet) {
tabStyle.width = finalTabWidth;
}
if (passedTabStyle && typeof passedTabStyle.flex === 'number') {
tabContainerStyle.flex = passedTabStyle.flex;
} else if (!isWidthSet) {
tabContainerStyle.flex = 1;
}
const accessibilityLabel =
route.accessibilityLabel || route.title;
return (
{
// eslint-disable-line react/jsx-no-bind
const { onTabPress, jumpToIndex } = this.props;
jumpToIndex(i);
if (onTabPress) {
onTabPress(scene);
}
}}
style={tabContainerStyle}
>
{icon}
{label}
{badge ? (
{badge}
) : null}
);
})}
);
在node_modules/react-navigation/src/views/TabView/TabBarBottom.js下插入红色部分,代码为render方法中的的return部分// 针对iOS
return (
{this.props.gameButton}
{routes.map((route: NavigationRoute, index: number) => {
const focused = index === navigation.state.index;
const scene = { route, index, focused };
const onPress = getOnPress(previousScene, scene);
const outputRange = inputRange.map(
(inputIndex: number) =>
inputIndex === index
? activeBackgroundColor
: inactiveBackgroundColor
);
const backgroundColor = position.interpolate({
inputRange,
outputRange: (outputRange: Array),
});
const justifyContent = this.props.showIcon ? 'flex-end' : 'center';
const extraProps = this._renderTestIDProps(scene) || {};
const { testID, accessibilityLabel } = extraProps;
return (
onPress
? onPress({ previousScene, scene, jumpToIndex })
: jumpToIndex(index)}
>
{this._renderIcon(scene)}
{this._renderLabel(scene)}
);
})}
);
3.使用的地方tabBarOptions里增加参数bgImgOptions
//设置Tab标签的属性
tabBarOptions: {
upperCaseLabel: false,
showIcon: true,//是否显示图标,默认关闭
showLabel: true,//是否显示label,默认开启
activeTintColor: 'white',//label和icon的前景色 活跃状态下(选中)
inactiveTintColor: '#FCFCFC',//label和icon的前景色 活跃状态下(未选中)
allowFontScaling: false,
style: Platform.OS === 'ios' ? iosTabBarStyle : androidTabBarStyle, //TabNavigator 的背景颜色
indicatorStyle: {//标签指示器的样式对象(选项卡底部的行)。安卓底部会多出一条线,可以将height设置为0来暂时解决这个问题
height: 0,
},
labelStyle: {//文字的样式
fontSize: 13,
marginTop: -5,
marginBottom: 5,
},
iconStyle: {//图标的样式
width: 48,
height:48,
},
bgImgOptions: {
showBgImg: "true",
width: ScreenWidth,
height: 80,
marginTop: -30,
bgImg: require('../img/tabicon/tab_bg.png'), // 此为TabBar添加背景图
gameButton:退出游戏 // 此为在TabBar中增加额外的View元素进行退出子业务模块操作
}
感谢大家的关注!