React Native ScrollableTabView的自定义tabBar

        react-native-scrollable-tab-view是一个非常好用的TabBar组件,支持滑动,可以实现标签超过屏幕宽度的情况。但是有时会需要实现比如提示未读个数、定制样式这些需求,那么已有的功能就不能满足需求了。现在实现一个类似下图可标记未读及数量的自定义TabBar。原图找不到了,就类似网易首页顶部的tabbar,包括显示数字。

基本用法git地址:https://github.com/brentvatne/react-native-scrollable-tab-view,一个简单的例子:
 <ScrollableTabView
	style={styles.container}
    locked={true}
   	tabBarUnderlineStyle={styles.indicator}
    tabBarBackgroundColor='#fff' 
    tabBarActiveTextColor="#485FF9"
    tabBarInactiveTextColor="#000000"
    tabBarTextStyle={styles.textSize}
    initialPage={0}
     renderTabBar={() => <DefaultTabBar />}>
		 <View style={{flex: 1}}>
        	<View style={{flex:1 ,width:'100%'}}>
        		<Text>界面1</Text>
        	</View>          
         </View>
         
         <View style={{flex: 1}}>
         	<View style={{flex:1 ,width:'100%'}}>
        		<Text>界面2</Text>
        	</View>   
         </View>
         
		 <View style={{flex: 1}}>
         	<View style={{flex:1 ,width:'100%'}}>
        		<Text>界面3</Text>
        	</View>
         </View>
         
		<View style={{flex: 1}}>
        	<View style={{flex:1 ,width:'100%'}}>
        		<Text>界面4</Text>
        	</View>      
        </View>
 </ScrollableTabView>

        属性renderTabBar就是tabbar组件。官方默认给了几个样式,如果实现自定义样式,就自己写一个组件然后赋值给它。

自定义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来实现我们想要的底部线的宽度,或实现移动时的伸缩效果,都可以通过这个来实现。

直接上自定义的tabbar
/**
 * @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 <View style={[styles.tabs, this.props.style, {backgroundColor: this.props.backgroundColor,}]}>

            {this.props.tabLabelNames.map((tab, page) => {
                return <TouchableOpacity key={tab.name} onPress={() => this.props.goToPage(page)} style={styles.tab}>

                    <Text
                        style={[styles.tabText, page === this.props.activeTab ? {color: this.props.activeTextColor} : {color: this.props.inactiveTextColor}, this.props.textStyle]}>{tab.name}</Text>

                    <View
                        style={[
                            (tab.showNum && tab.num !== 0) ? styles.tabNum : (tab.showIcon ? styles.tabDot : null),
                            ((tab.showNum && tab.num !== 0) || tab.showIcon) ? styles.show : styles.hide]}>
                        <Text
                            style={styles.tabNumText}>{(tab.showNum && tab.num !== 0) ? (tab.num > 99 ? '99+' : tab.num) : null}</Text>
                    </View>

                </TouchableOpacity>;
            })}

            <Animated.View
                style={[
                    tabUnderlineStyle,
                    {
                        transform: [
                            {translateX},
                        ]
                    },
                    this.props.underlineStyle,
                ]}
            />
        </View>;
    }

}

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;
例子
 <ScrollableTabView
	style={styles.container}
    locked={true}
   	tabBarUnderlineStyle={styles.indicator}
    tabBarBackgroundColor='#fff' 
    tabBarActiveTextColor="#485FF9"
    tabBarInactiveTextColor="#000000"
    tabBarTextStyle={styles.textSize}
    initialPage={0}
    renderTabBar={() => <CustomTabBar tabLabelNames={[
                        {name: '标签1', showNum: true, showIcon: false, num: this.state.num1},
                        {name: '标签2', showNum: false, showIcon: this.props.hasUnread},
                        {name: '标签3', showNum: false, showIcon: false},
                        {name: '标签4', showNum: false, showIcon: false}]}/>}>
		 <View style={{flex: 1}}>
         	<View style={{flex:1 ,width:'100%'}}>
        		<Text>界面1</Text>
        	</View>
         </View>
         
         <View style={{flex: 1}}>
         	<View style={{flex:1 ,width:'100%'}}>
        		<Text>界面2</Text>
        	</View>
         </View>
         
		 <View style={{flex: 1}}>
         	<View style={{flex:1 ,width:'100%'}}>
        		<Text>界面3</Text>
        	</View>	      
         </View>
         
		<View style={{flex: 1}}>
        	<View style={{flex:1 ,width:'100%'}}>
        		<Text>界面4</Text>
        	</View>               
        </View>
 </ScrollableTabView>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值