在APP页面中,首页往往会显示一个banner视图,定时循环滚动。那么类似于这样的一个广告展示功能,RN如何实现呢?
banner.gif
1、实现该功能涉及的知识点如下:
RN组件:
View, ScrollView, Image,TouchableOpacity, Dimensions, StyleSheet
其他知识:
定时器(setInterval,setTimeout),数组(Array),组件的数据传递(props),组件的数据更新(state)
2、实现无限滚动原理如下图:
例:有三张图片(A,B,C),实际是创建5个图片占位,(首尾为滚动备用)
向右移动.png 向左移动.png
定时器向右滚动.png
定时器向左滚动请模仿手动拖拽的操作即可。
3、代码实现:
开放属性:
static defaultProps = {
showIndex: 0,///显示的索引
autoScroll: false,//自动滚动
duration: 3000,//滚动的时间间距:2s
loopState: false,//是否循环滚动
showPageControl: false,//是否显示页码
style: null,//外部视图的样式
defaultSource: require('./image/failImage.png'),///默认显示图片
resizeMode: 'cover',///图片显示模式
imageStyle: { width: window.width, height: 120 },//图片的样式
failImagePath: require('./image/failImage.png'),//失败显示的图片require
imageUrlArray: null,//http的图片数组
imagePathArray: null,//本地图片的地址
tapImageAction: null,//图片单击回调
onMomentumScrollEnd: null,//图片滚动结束回调
renderPageComponent: null,//绘制页码显示组件
renderLoadingComponent: null,//绘制加载显示组件
renderImageDescComponent: null,//绘制图片显示组件
currentPagePointerStyle: null,//当前显示页码的样式
otherPagePointerStyle: null,//其他页码的样式
}
核心事件:
滚动组件事件属性.png
滚动事件:
onAnimationEnd:
// 当一帧滚动结束的时候调用
onAnimationEnd(e) {
// 1.求出水平方向的偏移量
var offSetX = e.nativeEvent.contentOffset.x;
// 2.求出当前的页数
var currentPage = Math.floor(offSetX / this.props.style.width);
this.scrollToPage(currentPage, false);
}
/**
* 滚动至哪一页
* @param {页码} currentPage
* @param {是否自动*} auto
*/
scrollToPage(currentPage, auto) {
if (this.props.loopState) {
//向右最大页,需重置到第一页
if (currentPage >= this.state.count - 1) {
if (auto) {
this.refs.scrollView.scrollTo({ x: this.props.imageStyle.width * (currentPage), animated: auto });
//动画连贯处理
setTimeout(() => {
currentPage = 1;
this.refs.scrollView.scrollTo({ x: this.props.imageStyle.width * (currentPage), animated: false });
}, 500)
} else {
currentPage = 1;
this.refs.scrollView.scrollTo({ x: this.props.imageStyle.width * (currentPage), animated: false });
}
} else if (currentPage < 1) {
//向左到最小页,需重置到倒数第二页
if (auto) {
this.refs.scrollView.scrollTo({ x: this.props.imageStyle.width * (currentPage), animated: auto });
//动画连贯处理
setTimeout(() => {
currentPage = this.state.count - 2;
this.refs.scrollView.scrollTo({ x: this.props.imageStyle.width * (currentPage), animated: false });
}, 500)
} else {
currentPage = this.state.count - 2;
this.refs.scrollView.scrollTo({ x: this.props.imageStyle.width * (currentPage), animated: false });
}
} else {
if (auto) {
this.refs.scrollView.scrollTo({ x: this.props.imageStyle.width * (currentPage), animated: auto });
}
}
} else {
if (auto) {
this.refs.scrollView.scrollTo({ x: this.props.imageStyle.width * (currentPage), animated: auto });
}
}
this.setState({
currentPage: currentPage,
})
}
}
定时器操作事件:
/*定时器操作*/
/* 调用开始拖拽 */
onScrollBeginDrag() {
if (this.props.autoScroll && this.state.count > 1) {
// 停止定时器
this.stopTimer()
}
}
/*调用停止拖拽*/
onScrollEndDrag() {
if (this.props.autoScroll && this.state.count > 1) {
// 开启定时器
this.startTimer();
}
}
/*组件将要被移除方法*/
componnetWillUnmount() {
if (this.props.autoScroll && timer) {
this.stopTimer();
}
if (timer) {
timer = null;
}
}
//组件加载完成
componentDidMount() {
this.props.autoScroll && this.state.count > 1 && this.startTimer();
}
//停止定时器
stopTimer() {
clearInterval(timer);
timer = null;
}
// 开启定时器
startTimer() {
timer = setInterval(() => {
this.scrollToPage(this.state.currentPage + 1, true);
}, this.props.duration);
}
此外需注意,图片数据展示的位置,以及页码的正确展示。
LXScrollView.js 文件代码实现请查看
:https://github.com/HeXiuLian/XLReactNativeProject/blob/master/XLReactNative/src/component/XLScrollView.js
示例使用请查看GitHub地址:https://github.com/HeXiuLian/XLReactNativeProject
4、总结:根据这种思路,可以提升至自定义日历控件哦。
5、特别注意
使用时若遇到定时器无法释放时,请使用父组件,调用stopTimer() 方法停止定时器。
网友评论