react--动态添加tab和tab对应的界面

react--动态添加tab和tab对应的界面

情景描述
产品丢过来一个分类的功能:分几个类不固定,分类中的数据是一个列表,可分页、刷新。分析一下,数据不固定,就需要动态获取,大分类数据(有多少个分类)和分类中的列表数据都需要从接口中获取,这是一个比较常用的功能。

先上效果图:

5431497-5e37299226e844c5.gif
uu81y-x1sv4.gif

图中横向滑动的数据、分类下面的列表数据都是从接口得到的,要达到这样的效果,我们先分析一下,上面横向滑动的分类是一个scrollTab,react中有这样的开源项目,react-native-scrollable-tab-view(如果该项目可以满足你的需求,请忽略下面的内容)。下面的列表可以用FlatList来做,因为数据结构、页面样式相似,我们可以用一个界面就能完成。

分析完毕,下面我们一步一步来做,最终达成我们想要的效果。

第一步:导入react-native-scrollable-tab-view

使用npm将该控件导入到项目中:
npm install --save react-native-scrollable-tab-view
运行项目(运行Android为例):
react-native run-android

第二步:使用react-native-scrollable-tab-view

下面的代码是对ScrollableTabView的简单使用,更多属性见 react-native-scrollable-tab-view,其中
renderTabBar={() => <ClassificationTabBar tabNames={this._renderTabTitle()}/>}
{this._renderDynamicView()}会作具体说明,以下是ScrollableTabView的简单使用代码示例:

render() {
    return <View style={styles.container}>
                <ScrollableTabView
                    ref={(ScrollableTabView) => {
                        _scrollableTabView = ScrollableTabView;
                    }}//将该控件提取出来,_scrollableTabView指向该控件
                    renderTabBar={() => <ClassificationTabBar tabNames={this._renderTabTitle()}/>}//也可以使用DefaultTabBar,ScrollableTabBar
                    initialPage={0}//初始化哪一个界面
                    locked={false}//是否不允许滑动
                    scrollWithoutAnimation={true}
                    showsHorizontalScrollIndicator={false}
                    prerenderingSiblingsNumber={1}
                    tabBarActiveTextColor={'#cba000'}
                    tabBarInactiveTextColor={'#777'}>
                    {this._renderDynamicView()}
                </ScrollableTabView>
            </View>
}

上述代码中使用到了ClassificationTabBar ,ScrollableTabView中提供了DefaultTabBar,ScrollableTabBar,如果这两个可以满足需求,也可以使用这两个控件,跳过该步骤。ClassificationTabBar 中可自行定义tab样式风格,更具扩展性,以下是ClassificationTabBar 的全部代码,可直接使用:

/**
 * @author zhousx
 *
 * description:可滑动的动态 tabView
 */

import React, {Component} from 'react';
import {
    AppRegistry, Dimensions,
    StyleSheet,
    Text,
    TouchableOpacity,
    View
} from 'react-native';
import PropTypes from 'prop-types'
import {DEFAULT_FONT} from "../utils/FontUtils";
let {width, height} = Dimensions.get('window');

export default class ClassificationTabBar extends Component {
    static propTypes = {

        activeTab: PropTypes.number, // 当前被选中的tab下标
        tabs: PropTypes.array, // 所有tabs集合

        tabNames: PropTypes.array, // 保存Tab名称
    };  // 注意这里有分号


    render() {
        return (
            <View style = {styles.parent}>
                <View style={styles.tabs}>
                    {/*遍历。系统会提供一个tab和下标 调用一个自定义的方法*/}
                    {this.props.tabs.map((tab, i) => this.renderTabOption(tab, i))}
                </View>
                <View style = {{backgroundColor:'#fafafa',width:width,height:1}}/>
            </View>
        );
    }


///  处理tabbar的颜色和字体及图标
    renderTabOption(tab, i) {
        let color = this.props.activeTab === i ? "#cba000" : "#aaaaaa"; // 判断i是否是当前选中的tab,设置不同的颜色
        let color2 = this.props.activeTab === i ? "#cba000" : "#fff"; // 判断i是否是当前选中的tab,设置不同的颜色
        return (
            //因为要有点击效果 所以要引入可触摸组件
            <TouchableOpacity onPress={() => this.props.goToPage(i)} style={styles.tab} key={tab}>
                <View style={styles.tabItem}>
                    <Text style={{color: color, fontFamily: DEFAULT_FONT, marginTop: 15}}>
                        {this.props.tabNames[i]}
                    </Text>
                    <Text
                        style={{backgroundColor: color2, width: 40, height: 2, marginTop: 10}}/>
                </View>
            </TouchableOpacity>
        );
    }


}

const styles = StyleSheet.create({
    parent:{
        elevation: 2,
        shadowOffset: {
            width: 1, height: 2
        },
    },
    tabs: {
        flexDirection: 'row',
        height: 45,
    },

    tab: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },

    tabItem: {
        flexDirection: 'column',
        alignItems: 'center',
        width: 100
    },

});

ClassificationTabBar 类中用到了prop-types,这是一个属性校验的类,在react老的版本中不需要导入,在新版本中被分离出来,是一个呗广泛使用的工具,如果项目中导入了请忽略,如果没导入请使用npm下载:
npm install --save prop-types
其中

static propTypes = {

        activeTab: PropTypes.number, // 当前被选中的tab下标
        tabs: PropTypes.array, // 所有tabs集合

        tabNames: PropTypes.array, // 保存Tab名称
    };  // 注意这里有分号

tabNames为传递过来的tab的标题数组,也就是ScrollableTabView中传递过去的值:
renderTabBar={() => <ClassificationTabBar tabNames={this._renderTabTitle()}/>}
this._renderTabTitle()方法:

_renderTabTitle() {
        const texts = [];
        for (let i = 0; i < this.state.dataArray.length; i++) {
            const labelName = this.state.dataArray[i].typeName;
            texts.push(labelName);
        }
        return texts;
    }

this.state.dataArray是在请求完成之后set的值。

到此,tab已动态设置完成,接下来需要动态添加列表页面。

第三步:动态添加列表页面

动态添加的类表页面的个数需要根据请求返回的分类的个数来确定,所以需要遍历分类个数来动态添加列表界面,因为我这边列表界面的样式都相同,所以把列表界面封装为一个Compoent,然后将参数传给列表界面,多个样式道理也相同。
下面是动态添加界面的代码:

_renderDynamicView() {
        const _views = [];
        for (let i = 0; i < this.state.dataArray.length; i++) {
            const labelName = this.state.dataArray[i].typeName;
            const classificationId = this.state.dataArray[i].id;
            console.log('labelName = ' + labelName);
            _views.push(<View
                style={styles.container} tabLabel={labelName} key={i}>
                <SecondClassificationView classificationId={classificationId} {...this.props}/>
            </View>);
        }
        return _views;
    }

将分类id传递给Component,在这里也就是SecondClassificationView ,然后通过ID去获取不同的数据,SecondClassificationView 是一个简单的继承Component的控件:

以下是SecondClassificationView 的部分代码:

export default class SecondClassificationView extends Component<props> {

    static propTypes = {
        classificationId: PropsTypes.number,
    };

    constructor(props) {
        super(props);
        this.state = {
            dataArray: [],
            isRefreshing: false
        }
    }

render() {
        const {navigation} = this.props;
        return <View
            style={styles.container}>
            <FlatList
                data={this.state.dataArray}
                renderItem={
                    (data) =>
                        <TouchableOpacity activeOpacity={0.5}
                                          onPress={() => {
                                              
                                          }}>
                            <View style={styles.item}>
                                <Image
                                    style={{marginLeft: 20, height: 18, width: 18,}}
                                    source={require('../../res/images/pic_book_head.png')}/>
                                <Text style={styles.text}>{data.item.bookName}</Text>
                            </View>
                        </TouchableOpacity>
                }
                ItemSeparatorComponent={
                    () => this._renderSeparator()
                }
                ListEmptyComponent={
                    () => this._renderEmpty()
                }
                refreshing={this.state.isRefreshing}
                onRefresh={
                    () => {
                        this._onRefresh()
                    }
                }
            />
        </View>
    }
}

至此,动态添加tab和tab对应界面的所有步骤就完成了,如果有问题的地方,请在下方留言,看到我会第一时间回复!
如果对你有帮助,点个赞呗!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值