import React, { Component, ReactNode } from 'react'; import { Text, TouchableOpacity, StyleSheet, TextStyle, ImageStyle, ViewStyle, ImageSourcePropType, StyleProp, DeviceEventEmitter, EmitterSubscription, } from 'react-native'; import { TabBarBottomProps } from 'react-navigation'; import { Theme } from '../styles'; import * as Animatable from 'react-native-animatable'; interface TabBarResourcesProps { /** 标题 */ title: string[]; /** 选中时的icon资源 */ iconActive: ImageSourcePropType[]; /** 没选中时的icon资源 */ iconInActive: ImageSourcePropType[]; } interface TabBarProps extends TabBarBottomProps { /** 数据资源数组 */ resources: TabBarResourcesProps[]; /** 底部分隔线颜色, 默认 borderColor */ topLineColor?: string; /** 选中时的标题颜色, 默认 theme */ activeTitleColor: string; /** 非选中时的标题颜色, 默认 fontColor */ inactiveTitleColor: string; /** 整体样式 */ style?: ViewStyle; /** 标题样式 */ titleStyle?: StyleProp; /** icon样式 */ iconStyle?: StyleProp; /** tab高度 */ height?: number; /** 背景组件 */ backgroundComponent?: ReactNode; /** tab点击回调函数 */ onPress: (index: number, routeName: string, navigation) => void; } interface TabBarBottomOwnState { visible: boolean; } const showNoti = 'TABBARBOTTOM_SHOW'; const hideNoti = 'TABBARBOTTOM_HIDE'; const H = px2dp(100) + Theme.iPhoneXBottom; class TabBarBottom extends Component { tabConfigs: any[] = new Array(); showEmitter: EmitterSubscription; hideEmitter: EmitterSubscription; itemImgs: any[]; view: Animatable.View; static defaultProps = { topLineColor: Theme.borderColor, activeTitleColor: Theme.theme, inactiveTitleColor: Theme.fontColor, height: px2dp(100), }; /** * show TabBar */ static show() { DeviceEventEmitter.emit(showNoti); } /** * hide TabBar */ static hide() { DeviceEventEmitter.emit(hideNoti); } constructor(props) { super(props); props.resources.forEach((item, idx) => { this.tabConfigs.push({ name: item.title, activeIcon: item.iconActive || null, inActiveIcon: item.iconInActive || null, }); }); this.state = { visible: true, }; this.itemImgs = new Array(props.resources.length).fill(''); } componentDidMount() { this.showEmitter = DeviceEventEmitter.addListener(showNoti, () => { if (!this.state.visible) { this.setState({ visible: true }, this._barAnima); } }); this.hideEmitter = DeviceEventEmitter.addListener(hideNoti, () => { if (this.state.visible) { this.setState({ visible: false }, this._barAnima); } }); } componentWillUnmount() { if (this.showEmitter) this.showEmitter.remove(); if (this.hideEmitter) this.hideEmitter.remove(); } _barAnima = () => { if (this.view) { this.view[this.state.visible ? 'slideInUp' : 'slideOutDown'](); } } _changeIndex = (index, routeName) => { if (this.itemImgs[index]) { this.itemImgs[index]['swing'](); } if (this.props.onPress) { this.props.onPress(index, routeName, this.props.navigation); } else { this.props.navigation.navigate({ routeName }); } } render() { const { navigation, titleStyle, iconStyle, style, topLineColor, activeTitleColor, inactiveTitleColor, height, backgroundComponent } = this.props; const tabRoutes = navigation.state.routes || []; const tabs = tabRoutes.map((item, index) => { return { ...item, ...this.tabConfigs[index], }; }); const currentIndex = navigation.state.index || 0; return ( this.view = r} duration={300} easing={'ease-in-out'} style={[styles.tab, style, { borderTopColor: topLineColor }]} useNativeDriver> {backgroundComponent} {tabs.map((item, index) => { let isSelected = currentIndex === index; return ( { this._changeIndex(index, item.routeName); }} activeOpacity={0.8} > this.itemImgs[index] = r} duration={500} easing={'ease-in'} source={isSelected ? item.activeIcon : item.inActiveIcon} style={[styles.img, iconStyle]} /> {item.name} ); })} ); } } const styles = StyleSheet.create({ tab: { position: 'absolute', left: 0, right: 0, bottom: 0, height: H, alignItems: 'flex-start', flexDirection: 'row', backgroundColor: Theme.white, borderTopWidth: Theme.borderWidth, } as ViewStyle, item: { flex: 1, alignItems: 'center', justifyContent: 'center', }, img: { width: px2dp(44), height: px2dp(44), }, text: { marginTop: px2dp(8), fontSize: px2dp(20), }, }); export default TabBarBottom;