基本用法git地址:https://github.com/brentvatne/react-native-scrollable-tab-view,一个简单的例子:react-native-scrollable-tab-view是一个非常好用的TabBar组件,支持滑动,可以实现标签超过屏幕宽度的情况。但是有时会需要实现比如提示未读个数、定制样式这些需求,那么已有的功能就不能满足需求了。现在实现一个类似下图可标记未读及数量的自定义TabBar。原图找不到了,就类似网易首页顶部的tabbar,包括显示数字。
}>
界面1
界面2
界面3
界面4
属性renderTabBar就是tabbar组件。官方默认给了几个样式,如果实现自定义样式,就自己写一个组件然后赋值给它。
propTypes: {
goToPage: PropTypes.func,
activeTab: PropTypes.number,
tabs: PropTypes.array,
backgroundColor: PropTypes.string,
activeTextColor: PropTypes.string,
inactiveTextColor: PropTypes.string,
scrollOffset: PropTypes.number,
style: ViewPropTypes.style,
tabStyle: ViewPropTypes.style,
tabsContainerStyle: ViewPropTypes.style,
textStyle: Text.propTypes.style,
renderTab: PropTypes.func,
underlineStyle: ViewPropTypes.style,
onScroll: PropTypes.func,
}
ScrollableTabView的变量有上述这些,可以通过this.props.属性名来使用。比如:this.props.activeTab,是当前选择的tab,那么我们就可以利用这个属性来知道当前选择的是哪个tab。
另外:this.props.containerWidth是tabbar的长度,this.props.tabs.length是tabbar的标签个数。通过这两个,可以实现底部那条选中哪个标签移动到哪个标签下的底部线的样式。
还有,底部线移动的动画要怎么实现呢?在源码里看到这段注释:
// Animated.add and Animated.divide do not currently support listeners so
// we have to polyfill it here since a lot of code depends on being able
// to add a listener to `scrollValue`. See https://github.com/facebook/react-native/pull/12620.
也就是说ScrollableTabView通过scrollValue来实现了一个组合动画,就直接使用this.props.scrollValue来使用已经实现的底部线的动画,可以通过动画的插值函数interpolate来实现我们想要的底部线的宽度,或实现移动时的伸缩效果,都可以通过这个来实现。
/**
* @desc ScrollableTabView的自定义tabBar组件,赋值给renderTabBar
* 属性tabLabelNames,来记录需要的属性:showNum 是否显示数字,num 数量,showIcon 是否只展示小圆点。
* @author MaRui
*/
import React from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Animated,
} from 'react-native';
class CustomTabBar extends React.Component {
constructor(props) {
super(props);
}
render() {
const containerWidth = this.props.containerWidth;
const numberOfTabs = this.props.tabs.length;
const tabUnderlineStyle = {
position: 'absolute',
width: containerWidth / numberOfTabs,
height: 4,
backgroundColor: 'navy',
bottom: 0,
justifyContent: 'center'
};
const translateX = this.props.scrollValue.interpolate({
inputRange: [0, 1],
outputRange: [0, containerWidth / numberOfTabs],
});
return
{this.props.tabLabelNames.map((tab, page) => {
return this.props.goToPage(page)} style={styles.tab}>
{tab.name}
{(tab.showNum && tab.num !== 0) ? (tab.num > 99 ? '99+' : tab.num) : null}
;
})}
;
}
}
const styles = StyleSheet.create({
tab: {
flexDirection: 'row',
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
tabs: {
height: 45,
flexDirection: 'row',
justifyContent: 'space-around'
},
tabText: {
fontSize: 14
},
tabNum: {
borderRadius: 10,
backgroundColor: '#E72E2E',
height: 20,
minWidth: 20,
paddingHorizontal: 2,
marginLeft: 2,
alignItems: 'center',
justifyContent: 'center'
},
tabNumText: {
color: 'white',
fontSize: 10,
textAlign: 'center',
lineHeight: 20,
minWidth: 20
},
tabDot: {
borderRadius: 8,
marginLeft: 2,
height: 8,
width: 8,
backgroundColor: '#E72E2E'
},
show: {
display: 'flex'
},
hide: {
display: 'none'
}
});
export default MineTabBar;
}>
界面1
界面2
界面3
界面4