重置UICollectionView上的滚动

55

我有一个水平的 UICollectionView,它能够正常滚动。当我点击某个元素时,我会更新我的数据并调用 reloadData。这样做是有效的,并且新的数据也能在 UICollectionView 中显示出来。

问题在于,滚动位置没有改变,仍然停留在最后一个位置。我想将滚动重置到顶部(或者在我的情况下是左侧)。我该如何做到这一点?


你能在遇到这个问题时展示一下你的代码吗?我正在尝试让我的滚动视图在重新加载数据时不滚动,哈哈,我遇到了与你相反的问题! - Wayne Filkins
9个回答

175

您需要使用setContentOffset:方法。它需要一个CGPoint作为参数,您可以使用CGPointMake设置任何您想要的值,但如果您希望返回到集合视图的最开始位置,您可以简单地使用CGPointZero。

[collectionView setContentOffset:CGPointZero animated:YES];

如果CollectionView启用了刷新视图,它将会显示刷新视图。 - jasonhao
1
+1 setContentOffset 帮助我在 UIScrollView 上也解决了这个问题。 - NeverHopeless
32
如果你正在使用 contentInsets,你可以使用以下的点作为内容偏移量 CGPointMake(-collectionView.contentInset.left, -collectionView.contentInset.top) - TPoschel
2
对我来说,被接受的答案(scrollToItemAtIndexPath)会将滚动重置为第一行,这会使页眉项(viewForSupplementaryElementOfKind)不可见。使用setContentOffset到CGPointZero可以将滚动放置在完全顶部,包括任何页眉单元格。 - Scott Heaberlin
2
它还有一个优点,即无需验证索引路径是否存在(例如:空集合视图)。 - Adrian

34

你可以使用这种方法滚动到任何你想要的项目:

- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath 
               atScrollPosition:(UICollectionViewScrollPosition)scrollPosition 
                       animated:(BOOL)animated

1
也不允许偏移量。 - Dermot
算了,下面的注释解决了它。 [collectionView setContentOffset:CGPointZero animated:YES]; - inigo333
4
顺便提一下,如果你将animated设置为NO并将其包含在动画块中(例如UIView withSpring...),则可以为滚动设置自定义的动画样式/速度。 - Dermot
请注意,此实现还将调用滚动委托方法,这正是我想要的。谢谢。 - ClockWise
1
这个解决方案更适合滚动到特定的项目。"setContentOffset" 更适合简单地滚动到顶部,更好且更安全。这个解决方案需要一些检查来避免运行时异常。 - Abdurrahman Mubeen Ali
警告:如果内容仍在加载中,这可能会导致iOS 12及更早版本崩溃。我建议使用使用setContentOffset方法的方式。 - Alain Stulz

23

我在我的应用的不同部分经常使用它,所以我扩展了UIScrollView,使其可以用于任何滚动视图和滚动视图子类:

extension UIScrollView {        
    /// Sets content offset to the top.
    func resetScrollPositionToTop() {
        self.contentOffset = CGPoint(x: -contentInset.left, y: -contentInset.top)
    }
}

所以每当我需要重置位置时:

self.collectionView.resetScrollPositionToTop()

13

在Swift中:

collectionView.setContentOffset(CGPointZero, animated: true)

如果您离开了包含集合视图的视图,并在第二个视图控制器中进行了更改,需要在返回时更新集合视图:

@IBAction func unwindTo_CollectionViewVC(segue: UIStoryboardSegue) {
    //Automatic table reload upon unwind
    viewDidLoad()
    collectionView.reloadData()
    collectionView.setContentOffset(CGPointZero, animated: true)
}

在我的情况下,取消选中非常好,因为viewDidLoad调用将更新CoreData上下文,reloadData调用将确保collectionView更新以反映新的CoreData上下文,然后contentOffset将确保表格回到顶部。


7
如果您的视图控制器包含安全区域,请使用以下代码:
collectionView.setContentOffset(CGPointZero, animated: true)

无法正常工作,因此您可以使用通用扩展:

extension UIScrollView {
    func scrollToTop(_ animated: Bool) {
        var topContentOffset: CGPoint
        if #available(iOS 11.0, *) {
            topContentOffset = CGPoint(x: -safeAreaInsets.left, y: -safeAreaInsets.top)
        } else {
            topContentOffset = CGPoint(x: -contentInset.left, y: -contentInset.top)
        }
        setContentOffset(topContentOffset, animated: animated)
    }
}

不鼓励只提供代码的答案。请点击编辑并添加一两段概括您的代码如何回答问题,或者解释您的答案与先前答案的区别。谢谢。 - Nick
这是唯一考虑到safeAreaInsets的答案。其他所有答案都将我的collectionView滚动到了错误的位置。 - Steven Baughman

6
在我的情况下,CGPointZero会移动集合视图的内容,因为您没有考虑到内容插入。这是适合我的做法:
    CGPoint topOffest = CGPointMake(0,-self.collectionView.contentInset.top);
    [self.collectionView setContentOffset:topOffest animated:YES];

简单而干净! - Evgeny Fedin

4

很抱歉,我在写这篇文章时无法进行评论,但是我正在使用一个UINavigationController,而CGPointZero本身并没有让我到达最顶部,所以我不得不使用以下代码。

CGFloat compensateHeight = -(self.navigationController.navigationBar.bounds.size.height+[UIApplication sharedApplication].statusBarFrame.size.height);
[self.collectionView setContentOffset:CGPointMake(0, compensateHeight) animated:YES];

希望这能帮助未来的某些人。干杯!

2
为了处理一个UINavigationController和一个透明的导航栏,我需要计算额外的顶部偏移量,以完美匹配第一个元素的位置。
Swift 1.1代码:
     let topOffest = CGPointMake(0, -(self.collectionView?.contentInset.top ?? O))
     self.collectionView?.setContentOffset(topOffest, animated: true)

干杯!


0
  • SWIFT 4.2 解决方案- 假设我有一个tableView,每个tableViewCell都包含一个HorizontalCollectionView 由于单元格的重用,即使第一个tableViewCell向下滚动到第4页,其他单元格也会被设置为第4页。

在这种情况下,可以采用以下方法- 在tableView的cellForRowAt函数中, let cell = //使用deque声明一个单元格 cell.myCollectionView.contentOffset = CGPoint(x:0,y:0)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接