cic*_*rgo 39

如果您的数据是静态的并且您想要一种循环行为,则可以执行以下操作:

var dataSource = ["item 0", "item 1", "item 2"]

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return Int.max // instead of returnin dataSource.count
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let itemToShow = dataSource[indexPath.row % dataSource.count]
    let cell = UICollectionViewCell() // setup cell with your item and return
    return cell
}
Run Code Online (Sandbox Code Playgroud)

基本上你对你的集合视图说你有大量的单元格(Int.max不会是无限的,但可能会这样做),并且你使用%运算符访问你的数据源.在我的例子中,我们最终得到"项目0","项目1","项目2","项目0","项目1","项目2"....

我希望这有帮助 :)

  • 返回`Int.max`崩溃模拟器:( (34认同)
  • 很优雅的解决方案 只是一个补充 - 如果你想让集合从头开始向左滚动,你可以使用:CollectionView.scrollToItem()并在初始化之后给它一些大的值. (7认同)
  • 你确定这不会引发性能问题吗? (3认同)
  • @tarrball是的,但是单元格重用机制只能解决内存问题,如果单元格的大小取决于它显示的数据,并且您在`heightForRowAtIndexPath`或`sizeForItemAtIndexPath`中计算它们的大小/高度,这些方法将称为您的`numberOf .. InSection`返回的次数很多。我猜这可能会导致性能问题?即使我进行一些缓存,这里仍然会有数百万不必要的调用。 (2认同)
  • @tarrball,不!由于UITableView和UICollectionView是UIScrollView的子类,因此系统会在初始化滚动视图以确定其contentSize时计算每个单元格的大小,因此我尚未在实际应用中测试此方法,只是担心我可能会提出性能问题,也很高兴知道您已经实现了此功能,并且运行良好。 (2认同)
  • 如果用户从一开始向左滑动会发生什么情况?会变成-1吗? (2认同)
  • 对于模拟器和设备的 Int(INT_MAX) 和 Int.max,它会崩溃。 (2认同)

Bio*_*tic 10

显然,最接近良好解决方案的是Manikanta Adimulam提出的.最干净的解决方案是在数据列表的开头添加最后一个元素,并将第一个元素添加到最后一个数据列表位置(例如:[4] [0] [1] [2] [3] [4] [ 0]),所以我们在触发最后一个列表项时滚动到第一个数组项,反之亦然.这适用于具有一个可见项的集合视图:

  1. 子类UICollectionView.
  2. 覆盖UICollectionViewDelegate并覆盖以下方法:

    public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let numberOfCells = items.count
        let page = Int(scrollView.contentOffset.x) / Int(cellWidth)
        if page == 0 { // we are within the fake last, so delegate real last
            currentPage = numberOfCells - 1
        } else if page == numberOfCells - 1 { // we are within the fake first, so delegate the real first
            currentPage = 0
        } else { // real page is always fake minus one
           currentPage = page - 1
        }
        // if you need to know changed position, you can delegate it
        customDelegate?.pageChanged(currentPage)
    }
    
    
    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let numberOfCells = items.count
        if numberOfCells == 1 {
            return
        }
        let regularContentOffset = cellWidth * CGFloat(numberOfCells - 2)
        if (scrollView.contentOffset.x >= cellWidth * CGFloat(numberOfCells - 1)) {
            scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x - regularContentOffset, y: 0.0)
        } else if (scrollView.contentOffset.x < cellWidth) {
            scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x + regularContentOffset, y: 0.0)
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 覆盖UICollectionView中的layoutSubviews()方法,以便始终为第一个项目创建正确的偏移量:

    override func layoutSubviews() {
        super.layoutSubviews()
    
        let numberOfCells = items.count
        if numberOfCells > 1 {
            if contentOffset.x == 0.0 {
                contentOffset = CGPoint(x: cellWidth, y: 0.0)
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 覆盖init方法并计算单元格尺寸:

    let layout = self.collectionViewLayout as! UICollectionViewFlowLayout
    cellPadding = layout.minimumInteritemSpacing
    cellWidth = layout.itemSize.width
    
    Run Code Online (Sandbox Code Playgroud)

奇迹般有效!如果要在具有多个可见项的集合视图中实现此效果,请使用此处发布的解决方案.

  • 我使用了一个非常相似的解决方案。这适用于使用分页并一次显示一个单元格的 collectionViews。我还使用 collectionView(sizeForItemAt indexPath) 函数根据设备宽度调整单元格的大小,接受的答案会使应用程序崩溃,因为它为每个单元格设置了大小......所以制作一个大得离谱的集合不会在我的情况下工作。 (3认同)

Vis*_*ngh 6

我已经在 中实现了无限滚动UICollectionView。使代码在 github 中可用。你可以尝试一下。它在 swift 3.0 中。

无限滚动

您可以使用 pod 添加它。使用方法非常简单。只需初始化InfiniteScrollingBehaviour如下即可。

infiniteScrollingBehaviour = InfiniteScrollingBehaviour(withCollectionView: collectionView, andData: Card.dummyCards, delegate: self)
Run Code Online (Sandbox Code Playgroud)

并实现所需的委托方法以返回配置的UICollectionViewCell. 示例实现如下所示:

func configuredCell(forItemAtIndexPath indexPath: IndexPath, originalIndex: Int, andData data: InfiniteScollingData, forInfiniteScrollingBehaviour behaviour: InfiniteScrollingBehaviour) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellID", for: indexPath)
        if let collectionCell = cell as? CollectionViewCell,
            let card = data as? Card {
            collectionCell.titleLabel.text = card.name
        }
        return cell
    }
Run Code Online (Sandbox Code Playgroud)

它将在原始数据集中添加适当的前导和尾随边界元素,并调整 collectionView 的contentOffset.

在回调方法中,它将为您提供原始数据集中某个项目的索引。


Jož*_* Ws 5

测试代码

我通过简单地重复单元 x 次来实现这一点。如下,

声明您想要有多少个循环

let x = 50
Run Code Online (Sandbox Code Playgroud)

实施numberOfItems

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return myArray.count*x // large scrolling: lets see who can reach the end :p
}
Run Code Online (Sandbox Code Playgroud)

添加此实用程序函数来计算arrayIndex给定的 indexPath 行

func arrayIndexForRow(_ row : Int)-> Int {
    return row % myArray.count
}
Run Code Online (Sandbox Code Playgroud)

实施cellForItem

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myIdentifier", for: indexPath) as! MyCustomCell
    let arrayIndex = arrayIndexForRow(indexPath.row)
    let modelObject = myArray[arrayIndex]
    // configure cell
    return cell
}
Run Code Online (Sandbox Code Playgroud)

collectionView添加实用程序函数以滚动到给定索引的中间

func scrollToMiddle(atIndex: Int, animated: Bool = true) {
    let middleIndex = atIndex + x*yourArray.count/2
    collectionView.scrollToItem(at: IndexPath(item: middleIndex, section: 0), at: .centeredHorizontally, animated: animated)
}
Run Code Online (Sandbox Code Playgroud)