您的位置:首页 > Web前端 > React

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

2017-09-05 22:23 525 查看
上一节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的指示线显示出来。

欢迎入群,欢迎交流,大牛勿喷~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: