美文网首页
RN ScrollView循环滚动视图

RN ScrollView循环滚动视图

作者: 墨香茉香 | 来源:发表于2019-07-22 18:11 被阅读0次

    在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() 方法停止定时器。

    相关文章

      网友评论

          本文标题:RN ScrollView循环滚动视图

          本文链接:https://www.haomeiwen.com/subject/phewlctx.html