React Native带你实现scrollable-tab-view(二)

来源:互联网 发布:sql注入绕过单引号 编辑:程序博客网 时间:2024/06/06 19:02

上一节React Native带你实现scrollable-tab-view(一)中我们最后实现了我们scrollable-tab-view的效果为:
这里写图片描述

代码为:

/** * @author YASIN * @version [React-Native Pactera V01, 2017/9/5] * @date 2017/9/5 * @description index */......    render() {        return (            <View                style={styles.container}            >                {/*渲染tabview*/}                {this._renderTabView()}                <ScrollView                    style={styles.scrollStyle}                    pagingEnabled={true}                    horizontal={true}                >                    {['页面一', '页面二', '页面三'].map((item, index)=> {                        return (                            <Text                                key={item + index}                                style={{                                    width: screenW,                                    flex: 1,                                }}                            >                                {item}                            </Text>                        );                    })}                </ScrollView>            </View>        );    }    /**     * 渲染tabview     * @private     */    _renderTabView() {        return (            <View                style={styles.tabContainer}            >                {['页面一', '页面二', '页面三'].map((item, index)=> {                    return (                        <TouchableOpacity                            key={item + index}                            style={styles.tabStyle}                        >                            <Text>{item}</Text>                        </TouchableOpacity>                    );                })}            </View>        );    }}......

作为一个第三方性的组件,这样写耦合性太高,不太容易复用,所以我们改改:
index.js:

export default class ScrollableTab extends Component {    static propTypes = {}    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {};    }    render() {        return (            <View                style={styles.container}            >                {/*渲染tabview*/}                {this._renderTabView()}                {/*渲染主体内容*/}                {this._renderScrollableContent()}            </View>        );    }    /**     * 渲染tabview     * @private     */    _renderTabView() {        let tabParams = {            tabs: this._children().map((child)=>child.props.tabLabel),        };        return (            <DefaultTabBar                {...tabParams}            />        );    }    /**     * 渲染主体内容     * @private     */    _renderScrollableContent() {        return (            <Animated.ScrollView                style={styles.scrollStyle}                pagingEnabled={true}                horizontal={true}            >                {this.props.children}            </Animated.ScrollView>        );    }    /**     * 获取子控件数组集合     * @param children     * @returns {*}     * @private     */    _children(children = this.props.children) {        return React.Children.map(children, (child)=>child);    }}

然后把之前的渲染_renderTabView的代码变成了一个单独的组件DefaultTabBar.js,然后传入tabs即为我们需要的tab内容:

DefaultTabBar.js:

/** * @author YASIN * @version [React-Native Pactera V01, 2017/9/5] * @date 17/2/23 * @description DefaultTabBar */import React, {    Component, PropTypes,} from 'react';import {    View,    Text,    StyleSheet,    TouchableOpacity,    Dimensions,} from 'react-native';const screenW = Dimensions.get('window').width;const screenH = Dimensions.get('window').height;export default class DefaultTabBar extends Component {    static propTypes = {        tabs: PropTypes.array,    }    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {};    }    render() {        return (            <View style={styles.container}>                {this.props.tabs.map((name, page) => {                    return this._renderTab(name, page);                })}            </View>        );    }    /**     * 渲染tab     * @param name 名字     * @param page 下标     * @private     */    _renderTab(name, page) {        return (            <TouchableOpacity                key={name + page}                style={styles.tabStyle}            >                <Text>{name}</Text>            </TouchableOpacity>        );    }}const styles = StyleSheet.create({    container: {        width: screenW,        flexDirection: 'row',        alignItems: 'center',        height: 50,    },    tabStyle: {        flex: 1,        alignItems: 'center',        justifyContent: 'center',    }});

然后我们用的时候只需要渲染自己的内容模块就可以了:

export default class ScrollTabDemo extends Component {    render() {        return (            <View style={styles.container}>                <ScrollableTab>                    {['页面一', '页面二', '页面三'].map((item, index)=> {                        return (                            <Text                                tabLabel={item}                                key={item + index}                                style={{                                    width: screenW,                                    flex: 1,                                }}                            >                                {item}                            </Text>                        );                    })}                </ScrollableTab>                {/*<App/>*/}            </View>        );    }}

哈哈~~ 是不是很熟悉呢? scrollable-tab-view第三方库就是这么用的,没有啥高大上的东西,只是把公共部分提取出来了,这也就是自定义组件存在的目的。

然后运行代码,跟我们一开始一样的效果~~~

接下来我们得知道我们每次滑动scrollview后我们停留在哪个页面,主要就是用到scrollview的onMomentumScrollBegin跟onMomentumScrollEnd属性,这两个是干嘛的呢?就是当滑动开始跟滑动结束时候的回调。

怎么拿到我们的当前页面呢?
onMomentumScrollBegin跟onMomentumScrollEnd会返回event,event里面包含scrollview在y轴的偏移量,Math.round(y轴的偏移量/控件的宽度)即为当前页面。

有了思路我们就开动了哈~

获取控件的宽度应该是没问题哈,我们定义一个叫containerWidth的变量,然后默认宽度为屏幕宽:

render() {        return (            <View                style={styles.container}                onLayout={this._onLayout}            >                {/*渲染tabview*/}                {this._renderTabView()}                {/*渲染主体内容*/}                {this._renderScrollableContent()}            </View>        );    }
/**     * 获取控件宽度     * @param e     * @private     */    _onLayout = (e)=> {        let {width}=e.nativeEvent.layout;        if (this.state.containerWidth !== width) {            this.setState({                containerWidth: width,            });        }    }

好了,我们已经获取到我们控件的宽度了,于是我们开始处理_onMomentumScrollBeginAndEnd方法:

  /**     * 渲染主体内容     * @private     */    _renderScrollableContent() {        return (            <Animated.ScrollView                style={{width: this.state.containerWidth}}                pagingEnabled={true}                horizontal={true}                onMomentumScrollBegin={this._onMomentumScrollBeginAndEnd}                onMomentumScrollEnd={this._onMomentumScrollBeginAndEnd}            >                {this.props.children}            </Animated.ScrollView>        );    }
 /**     * scrollview开始跟结束滑动回调     * @param e     * @private     */    _onMomentumScrollBeginAndEnd = (e) => {        let offsetX = e.nativeEvent.contentOffset.x;        let page = Math.round(offsetX / this.state.containerWidth);        if (this.state.currentPage !== page) {            console.log('当前页面-->'+page);            this.setState({                currentPage: page,            });        }    }

我们运行代码:

这里写图片描述

既然我们拿到了当前当前页面页码,然后我们试着把对应的tab置为红色,没选中的为绿色:

于是我们把页码传入DefaultTabView:

 /**     * 渲染tabview     * @private     */    _renderTabView() {        let tabParams = {            tabs: this._children().map((child)=>child.props.tabLabel),            activeTab: this.state.currentPage,        };        return (            <DefaultTabBar                {...tabParams}                style={[{width: this.state.containerWidth}]}            />        );    }

然后在DefaultTabView中,如果当前tab的下标为activeTab就显示红色:

DefaultTabView.js:

/** * @author YASIN * @version [React-Native Pactera V01, 2017/9/5] * @date 17/2/23 * @description DefaultTabBar */import React, {    Component, PropTypes,} from 'react';import {    View,    Text,    StyleSheet,    TouchableOpacity,    Dimensions,} from 'react-native';const screenW = Dimensions.get('window').width;const screenH = Dimensions.get('window').height;export default class DefaultTabBar extends Component {    static propTypes = {        tabs: PropTypes.array,        activeTab: PropTypes.number,//当前选中的tab        style: View.propTypes.style,    }    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {};    }    render() {        return (            <View style={[styles.container, this.props.style]}>                {this.props.tabs.map((name, page) => {                    const isTabActive = this.props.activeTab === page;                    return this._renderTab(name, page, isTabActive);                })}            </View>        );    }    /**     * 渲染tab     * @param name 名字     * @param page 下标     * @param isTabActive 是否是选中的tab     * @private     */    _renderTab(name, page, isTabActive) {        let tabTextStyle = null;        //如果被选中的style        if (isTabActive) {            tabTextStyle = {                color:'green'            };        } else {            tabTextStyle = {                color:'red'            };        }        return (            <TouchableOpacity                key={name + page}                style={[styles.tabStyle]}            >                <Text style={[tabTextStyle]}>{name}</Text>            </TouchableOpacity>        );    }}const styles = StyleSheet.create({    container: {        width: screenW,        flexDirection: 'row',        alignItems: 'center',        height: 50,    },    tabStyle: {        flex: 1,        alignItems: 'center',        justifyContent: 'center',    }});

然后运行代码:

这里写图片描述

可以看到,我们简单的就可以玩起来了,好啦~ 这一节先到这里了,下一节我们来完成点击tab切换到指定页面,然后把tabview的指示线显示出来。

欢迎入群,欢迎交流,大牛勿喷~~

原创粉丝点击