iOS开发专题iOS 控件iOS开发实战

iOS手把手搭建·无限循环滚动视图

2017-03-23  本文已影响416人  Andy矢倉

原文:iOS手把手搭建·无限循环滚动视图

在大多数常规App开发当中,我们都会有产品运营栏的需求,也就是列表页或者产品顶部,又或者整个页面需要展示几个滚动的运营活动、产品、广告什么的,当然,也可能是一个自己实现的一个图片浏览器。
在早些年,这类需求大多都是从First逐个滚动到Last,然后再自动滚到First,技术上无非都是通过UIScrollView + Timer的方案,iOS开发往往都喜欢专注于用(xuan)户(ji)体(zhuang)验(bi)的,所以后来出现了无限循环滚动的体验。

得益于iOS6以后出现的UICollectionView控件,无论是滚动视图,还是做图片浏览,都降低了很多难度和代码量,但是它为了灵活性,官方没有做无限滚动Api,那么今天,我们就用UICollectionView来实现无限循环滚动视图。

这里使用UICollectionView管理Cell方式来减少代码量和复用Cell的内存优化,通过关闭scrollToItem(at:at:animated:)滚动动画来让用户无法发觉是代码在控制滚动,让用户产生错觉变成无限循环。

我们假设视图是在水平滚动,Cell是横屏全部宽度填充,然后设置paging属性为true以便滚动到边缘从而获得更好的体验。

揣测

原理:这么做依赖于有操作表的概念,这样我们就可以在收尾添加元素。好比如,你有一个包含三个项目的数组,想要他们无限循环的滚动,那就把首位元素拷贝插入到末尾,同时末尾元素拷贝一份插入到首部。演示如下:

OK,我们直接上代码:

private func setupDataForCollectionView() {
        let originalItems = ["One", "Two", "Three"]
        if let firstItem = originalItems.first, let lastItem = originalItems.last {
            var workItems = originalItems
            workItems.insert(lastItem, at: 0)
            workItems.append(firstItem)
            items = workItems
        }
}

那么我们得到的items的内部结构就是这样:

["Three", "One", "Two", "Three", "One"]

结构上就和假想图一致。

臆测

这个过程依赖于在首尾的indexPath需要关闭动画来实现,通过方法scrollToItem(at:at:animated:)实现。
该方法包含以下三个参数:

UICollectionViewScrollPosition控制滚动位置,假设CollectionView被设置了分页,如果是水平视图,我们希望它滚到左边那就为UICollectionViewScrollPosition.left,如果是垂直视图,希望它滚到顶部那就是UICollectionViewScrollPosition.top

下面我们来看看是演示情况:


如果是往前滚的话就正好相反:


实施

我们实现的关键技术点就是检测用户的滚动意图,这样才能触发scrollToItem(at:at:animated:)方法来实现我们的目的。
为了能做到这一点,我们需要实现UICollectionView的父类的UIScrollView的代理方法scrollViewDidEndDecelerating来检测滚动停止信号。
再通过检测contentOffset属性来判断具体位置。

override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    let contentOffsetX = scrollView.contentOffset.x
    let contentOffsetWhenFullyScrolledRight = (collectionView?.frame.width)! * CGFloat(items.count - 1)
    if contentOffsetX == contentOffsetWhenFullyScrolledRight {
        let indexPath = IndexPath.init(item: 1, section: 0)
        collectionView?.scrollToItem(at: indexPath, at: .left, animated: false)
    } else if contentOffsetX == 0 {
        let indexPath = IndexPath.init(item: (items.count - 2), section: 0)
        collectionView?.scrollToItem(at: indexPath, at: .left, animated: false)
    }
}

OK,我们来看下视图结构和对应的索引结构:


视图结构能清晰的解答:

总结

创建一个无限循环的滚动视图其实So Easy,也就五个步骤:

上一篇下一篇

猜你喜欢

热点阅读