1. 程式人生 > >React Native—使用ScrollableTabView實現APP底部導航欄(帶訊息圓點)

React Native—使用ScrollableTabView實現APP底部導航欄(帶訊息圓點)

icon_selected color:#d81e06

icon_unselected color:#515151

一、前言

這段時間在公司開始搞React Native開發,要對APP的主頁底部導航欄進行替換,尋找了多種方法,最後使用react-native-scrollable-tab-view庫的ScrollableTabView實現了想要的功能(控制Tab頁面的顯示和隱藏、帶訊息圓點指示器)。

元件的地址:https://www.npmjs.com/package/react-native-scrollable-tab-view

二、效果圖

訊息圓點位置、樣式可以自行設定引數來調整。

三、自定義的tabBar元件(關鍵程式碼)

實現這個導航欄的關鍵點在於自定義的tabBar元件。這個元件裡面實現選中頁面和非選中頁面的圖示切換和訊息圓點的渲染,很多控制邏輯都封裝在了裡面。以下是自定義元件的程式碼(各位可根據需要自行改造):

import React from 'react';

import PropTypes from 'prop-types';

import {

    View,

    Text,

    Button,

    Image,

    StyleSheet,

    TouchableOpacity,

    ViewPropTypes

} from 'react-native';



import {

    Badge

} from 'teaset';



/**

 * 2018-11-10

 * chenlw

 * work:自定義ScrollableTabViewPage的TabBar

 */

export default class MyTabBar extends React.Component {



    propTypes = {

        goToPage: PropTypes.func, // 跳轉到對應tab的方法

        activeTab: PropTypes.number, // 當前被選中的tab下標

        tabs: PropTypes.array, // 所有tabs集合

        goToPage: PropTypes.func,

        backgroundColor: PropTypes.string,

        activeTextColor: PropTypes.string,

        inactiveTextColor: PropTypes.string,

        textStyle: Text.propTypes.style,

        tabStyle: ViewPropTypes.style,

        renderTab: PropTypes.func,

        underlineStyle: ViewPropTypes.style,

    }



    //未選中的圖示

    tabUnselectedIcons = [

        require('./icons/icon_message_unselected.png'),

        require('./icons/icon_my_unselected.png'),

    ];

    //選中的圖示

    tabSelectedIcons = [

        require('./icons/icon_message_selected.png'),

        require('./icons/icon_my_selected.png'),

    ];



    constructor(props) {

        super(props);

    }



    static defaultProps = {

        activeTextColor: 'navy',

        inactiveTextColor: 'black',

        backgroundColor: null,

    };



    /**

     * 是否顯示該Tab

     * @param {*} pageIndex

     */

    isRenderTab(pageIndex) {

        let hideTabIndexSet = this.props.hideTabIndexSet;

        if (hideTabIndexSet) {

            return !hideTabIndexSet.has(pageIndex);

        }

        return true;

    }



    render() {

        return (

            <View style={[styles.tabs, { backgroundColor: this.props.backgroundColor }, this.props.style,]}>

                <View style={{ flex: 1, flexDirection: 'row' }}>

                    {this.props.tabs.map((name, pageIndex) => {

                        if (this.isRenderTab(pageIndex)) {

                            //判斷是否渲染該頁面

                            const isTabActive = this.props.activeTab === pageIndex;

                            return this.renderTab(name, pageIndex, isTabActive, this.props.goToPage);

                        }

                    })}

                </View>

            </View>

        );

    }



    renderTab(name, pageIndex, isTabActive, onPressHandler) {

        const { activeTextColor, inactiveTextColor, textStyle, } = this.props;

        const textColor = isTabActive ? activeTextColor : inactiveTextColor;

        const fontWeight = isTabActive ? 'bold' : 'normal';



        return (

            <View style={{ flex: 1 }}>

                <TouchableOpacity

                    style={{ flex: 1 }}

                    onPress={() => onPressHandler(pageIndex)}>

                    <View style={[styles.tab, this.props.tabStyle,]}>

                        {

                            this.renderTabBadge(name)

                        }

                        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>

                            {

                                this.renderTabIcon(pageIndex, isTabActive)

                            }

                            <Text style={{ color: textColor }}>{name}</Text>

                        </View>



                    </View>

                </TouchableOpacity>

            </View>

        );

    }



    /**

     顯示Tab的圖示

     * require指令不支援變數型別

     * @param {*} pageIndex

     * @param {*} isTabActive

     */

    renderTabIcon(pageIndex, isTabActive) {

        if (isTabActive) {

            return <Image source={this.tabSelectedIcons[pageIndex]}></Image>;;

        } else {

            return <Image source={this.tabUnselectedIcons[pageIndex]}></Image>;;

        }

    }



    /**

     * 顯示訊息紅點

     * @param {*} pageName

     */

    renderTabBadge(pageName) {

        switch (pageName) {

            case "訊息":

                return <Badge style={{ position: 'absolute', right: 5, top: 5, }} count={10} />;

            case "我的":

                return <Badge style={{ position: 'absolute', right: 5, top: 5, }} count={12} />;

        }

        return null;

    }



}



const styles = StyleSheet.create({

    tab: {

        flex: 1,

        alignItems: 'center',

        justifyContent: 'center',

    },

    tabs: {

        height: 50,

        flexDirection: 'row',

        // justifyContent: 'space-around',

        borderWidth: 2,

        borderTopWidth: 0,

        borderLeftWidth: 0,

        borderRightWidth: 0,

        borderColor: '#ccc',

    },

});

四、控制Tab頁面的顯示和隱藏

實現控制Tab頁面的顯示和隱藏的思想:通過一個Set集合來決定頁面是否隱藏,如果頁面的下標存在該Set集合內則不顯示,反之則顯示。關鍵程式碼有兩處,一處是主頁的隱藏頁面引數的初始化,程式碼如下:

constructor(props) {

        super(props);



        /**

         * 實現隱藏特定頁面的功能:把要隱藏的頁面下標加入hideTabIndexSet就可以實現,比如要隱藏訊息頁面,就hideTabIndexSet.add(0);

         * 注意:

         * (1)要將這個屬性傳遞到自定義tabBar的props,這樣自定義tabBar元件才能讀取資料。

         * (2)同時要修改ScrollableTabView元件的初始化頁面下標,不然顯示的頁面就有可能錯誤。

         */

        const hideTabIndexSet = new Set();

        //hideTabIndexSet.add(0);



        //初始化頁面的下標

        const initialPage = 0;



        this.state = {

            activeIndex: 0,

            hideTabIndexSet: hideTabIndexSet,

            initialPage: initialPage,

        }

    }

把hideTabIndexSet傳遞到MyTabBar裡面:

<MyTabBar hideTabIndexSet={this.state.hideTabIndexSet}></MyTabBar>

第二處是在MyTabBar元件裡面,控制頁面的隱藏,程式碼如下:

render() {

        return (

            <View style={[styles.tabs, { backgroundColor: this.props.backgroundColor }, this.props.style,]}>

                <View style={{ flex: 1, flexDirection: 'row' }}>

                    {this.props.tabs.map((name, pageIndex) => {

                        if (this.isRenderTab(pageIndex)) {

                            //判斷是否渲染該頁面

                            const isTabActive = this.props.activeTab === pageIndex;

                            return this.renderTab(name, pageIndex, isTabActive, this.props.goToPage);

                        }

                    })}

                </View>

            </View>

        );

    }

資源下載地址:

如果你覺得我寫的不錯,就關注我吧!