react-native-viewpager是一个轮播图组件,最近有一个需求是有一个测试题页面,我第一反应是用一个轮播图组件,只是把轮播图替换成轮播视图,每个视图里面内容比图片复杂一些而已。。。然而,我只是这么想想,实际做起来还不知道会遇到什么坑,开始踩坑吧。
npm install react-native-viewpager --save
一开始就遇到一个比较坑的问题,我直接谷歌搜索react-native-viewpager
出来的第一个一看是github上面的,点进去也叫这个名字,没毛病啊,跟着教程安装,输入安装命令:npm install rn-viewpager --save
,然后我挺纳闷,为啥安装名字变了,回到谷歌搜索往下翻了几个,好像都是这个组件,比较尴尬的是我安装一直失败,导致我照着教程写代码一直报错,无奈我直接在github 上搜索,结果出现在第一个的居然不是我之前搜出来的这个,搞了半天我连组件都安装错了,react-native-viewpager 这是正确的github地址。
接着看教程,太简短了。。简短到我怀疑人生,
var ViewPager = require('react-native-viewpager');
<ViewPager
dataSource={this.state.dataSource}
renderPage={this._renderPage}/>
现在这个时代谁还用es5,先把引入方式改一下:
import ViewPager from 'react-native-viewpager';
接着看,看这个结构是不是跟ListView组件一样一样的?先暂时不管配置参数,我的第一目标是先让视图轮播起来,这里也没写dataSource应该怎么定义,renderPage应该怎么渲染,我理所当然的认为跟listview是一样的,于是我的代码是这样写的:
const ds = new ListView.DataSource({
rowHasChanged: (r1,r2) => r1 !== r2
});
this.state = {
dataSource : ds.cloneWithRows(data),
}
<ViewPager
dataSource = {this.state.dataSource}
renderPage = {this._renderPage.bind(this)} />
_renderPage(rowData,sectionID,rowID) {
}
然后报错了:
哈哈哈,我就知道没这么简单,应该是dataSource出了问题,于是我又去找,总算找到这个是怎么用的了:
const ds = new ViewPager.DataSource({
pageHasChanged: (p1,p2) => p1 !== p1,
});
this.state = {
dataSource: viewPagerDs.cloneWithPages(data),
}
再模拟几条假的数据,就能看到轮播图效果了。
当然,我的任务远不止这些,考虑到我的实际项目需求,首先不能根据手势切换上一条下一条数据,只能点击上一题和下一题切换,所以我要先禁用手势切换。自动播放也不行,看一下配置参数:
dataSource
: this is require to provide pages data,
renderPage
: this is require to render page view,
autoPlay
: true to turn page automatically,
initialPage
: to set the index of the first page to load,
isLoop
: true to run in infinite scroll mode,
locked
: true to disable touch scroll,
onChangePage
: page change callback,
renderPageIndicator
: render custom ViewPager indicator. (是否显示小圆点)
initialPage
: show initially some other page than first page.
找到我需要的两个参数是autoPlay和locked,autoPlay是是否自动播放,设置为false,locked是是否锁定手势滚动,设置为true.
这一步很简单,然后可以看到默认的翻页小圆点样式是在图片下方的,而我希望小圆点在最上方,而且是红色,而且还有颜色透明度的变化和当前选中页的圆点大小比其他圆点大的效果,然后看一下参数,renderPageIndicator
值为true显示小圆点,但是我需要修改小圆点的样式,这里没有暴露出可以修改小圆点样式的属性,没办法,去找源码吧,把源码搜罗出来改改。顺便提一下,所有安装的组件都在node_modules中,在这个文件夹中修改文件除非重新react-native run-android
才会生效,所以可以把这个组件移动到跟pages,container等文件夹同级的libs文件夹下。
顺着renderPageIndicator
在ViewPage.js文件中找到关键代码:
renderPageIndicator(props) {
if (this.props.renderPageIndicator === false) {
return null;
} else if (this.props.renderPageIndicator) {
return React.cloneElement(this.props.renderPageIndicator(), props);
} else {
return (
<View style={styles.indicators}>
<DefaultViewPageIndicator {...props} />
</View>
);
}
},
可以看到这里的这个view装小圆点的外层视图了,看一下外层视图的样式:
indicators: {
flex: 1,
alignItems: 'center',
position: 'absolute',
bottom: 10,
left: 0,
right: 0,
backgroundColor: 'transparent',
},
再继续找小圆点的样式,在DefalutViewPageIndicator.js中:
dot: {
width: DOT_SIZE,
height: DOT_SIZE,
borderRadius: DOT_SIZE / 2,
backgroundColor: '#E0E1E2',
marginLeft: DOT_SAPCE,
marginRight: DOT_SAPCE,
},
curDot: {
position: 'absolute',
width: DOT_SIZE,
height: DOT_SIZE,
borderRadius: DOT_SIZE / 2,
backgroundColor: '#80ACD0',
margin: DOT_SAPCE,
bottom: 0,
},
很明显,dot就是未选中小圆点的样式,curDot就是选中小圆点的样式,然后等等!!不要急着改,万一下一个地方也用了这个组件但是样式跟现在的样式需求不一样呢?最好的办法就是从父组件传递样式属性到DefalutViewPageIndicator.js文件,(因为要修改的样式有点多,所以我直接就把整个style传递给子组件了),先弄清楚组件结构:DefalutViewPageIndicator.js是ViewPage.js的子组件,ViewPage.js是我的页面的子组件,要从我的页面传递样式给孙子组件:
我的页面:
<ViewPager
dataSource = {this.state.questionDataSource}
renderPage = {this._renderPage.bind(this)}
autoPlay = {false}
locked = {true}
dotViewStyle={{}}
dotStyle = {{}}
selectedDotStyle = {{}}/>
dotStyle和selectedDotStyle就是我自定义用来控制小圆点样式的属性,dotViewStyle是小圆点外层视图样式
在ViewPage.js中:
{this.renderPageIndicator({goToPage: this.goToPage,
pageCount: pageIDs.length,
activePage: this.state.currentPage,
scrollValue: this.state.scrollValue,
scrollOffset: this.childIndex,
dotViewStyle: PropTypes.object,//增加
dotStyle: this.props.dotStyle,//增加
selectedDotStyle: this.props.selectedDotStyle//增加
})}
propTypes: {
//...
animation: PropTypes.func,
initialPage: PropTypes.number,
//add by melody
dotStyle: PropTypes.object,//增加
selectedDotStyle: PropTypes.object,//增加
},
<View style={[styles.indicators,this.props.dotViewStyle]}>
<DefaultViewPageIndicator {...props} />
</View>
从父组件拿到这两个属性继续传递给DefalutViewPageIndicator.js:
在DefalutViewPageIndicator.js中:
propTypes: {
goToPage: React.PropTypes.func,
activePage: React.PropTypes.number,
pageCount: React.PropTypes.number,
//add by melody
dotStyle: React.PropTypes.object,//增加
selectedDotStyle: React.PropTypes.object,//增加
},
<View style={styles.dot}
/>
改为:
<View style={[styles.dot,this.props.dotStyle]} />
<Animated.View style={[styles.curDot, {left}]}
/>
改为:
<Animated.View style={[styles.curDot, this.props.selectedDotStyle, {left}]} />
再去修改样式已经能起作用了,但是我需要的样式改起来没我想象中的简单,不过我慢慢调吧,除了样式,还有最重要的是给上一题和下一题绑定事件。