自定义布局时,UICollectionView的contentOffset会发生变化

26

我有一个带有自定义UICollectionViewLayout的UICollectionView(实际上,我正在使用这个不错的布局)。

在viewDidLoad中,我设置contentOffset = CGPointZero。然而,在viewDidLoad之后,偏移量为-20,并且内容被向下推动,如下图所示:


图片

(它应该与线齐平)。我在接口构建器中加载集合视图布局。看起来我的问题非常类似于这个问题,然而那里的解决方法对我不起作用。

我尝试在我的布局实现中修改collectionViewContentSize以确保它始终大于collectionView的大小。虽然这意味着我可以滚动我的内容向下(它比collectionView的高度短),并隐藏额外的空间,但我也可以向上滚动查看它。

似乎没有什么有效的方法!


这个问题即使在今天(2023年)的UIKit中仍然存在着一个“软件错误”。它归结于(完全疯狂的)contentInsetAdjustmentBehavior系统的行为(它本不应该存在于UIKit中,只是愚蠢和愚笨)。问题出现在“.never”模式(任何人都会使用的唯一模式)上,当你在同一个屏幕上有复杂的滚动视图系统(如表格视图和/或集合视图)时,它们以不同的方式在视图周期的不同部分进行奇怪而令人困惑的交互。如果你构建真正复杂的屏幕,这将是一个让人头疼的问题。 - Fattie
还有一个更加令人困惑的问题,就是我在这里提到的完全没有记录的行为,可以在“奇怪微妙的陷阱”链接中找到:https://dev59.com/cmMk5IYBdhLWcg3w5Bzy#58292916 - Fattie
5个回答

49

我找到了这种情况发生的原因。请查看此问题的被接受答案: 在iOS 7中,状态栏和导航栏出现在我的视图边界上

实际上,我们可以在IB中(如果您使用Storyboard)或在viewDidLoad中设置UIViewController的edgesForExtendedLayoutautomaticallyAdjustsScrollViewInsets属性,它将解决我们的问题。

只是不要忘记检查此属性是否可用,因为在iOS6或更早版本中会导致崩溃:

if ([self respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) {
    self.automaticallyAdjustsScrollViewInsets = NO;
}

敬礼!


7
请注意,如果您的集合视图控制器包含在父视图控制器中,则必须在控制器上设置automaticallyAdjustsScrollViewInsets - zoul
我曾经遇到这样一个问题,我想放置一个collectionView,其中每个单元格的高度为74,宽度为30,并且每次从父视图控制器切换到另一个视图控制器时都会被偏移-44。我试了将近两个小时,尝试了很多错误的方法才解决了这个问题。谢谢。 - devdc
你所提到的被接受的答案并没有提及任何关于自定义布局的内容。 - bio
@bio,没错,尽管我认为在这种情况下它并不重要。 - alexey.metelkin

16

我能想到的唯一一个行为勉强可以接受的解决方案:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (self.collectionView.contentOffset.y < 0) {
        self.collectionView.contentOffset = CGPointMake(self.collectionView.contentOffset.x, 0.0);
    }
}

collectionViewContentSize方法中,除了将内容的高度设置为fmax(self.collectionView.frame.size.height + 20, [self stackedSectionHeight]),还会移除节头上方的空白,但也会移除顶部的“弹跳”效果。这是一个相当次优解,但比较可接受。

如果有更好的答案,我会接受它,或者如果我找到更好的答案,我会更新这个答案。


1
当我使用水平布局时,我遇到了类似的问题。 - Avba
在垂直布局中,内容是正常的。但是当将布局对象更改为水平时,所有内容都消失了。 - Avba
我发现了相同的问题和解决方案。我只在iOS7 SDK上运行iOS7时才会遇到这个问题。最奇怪的是,另一个视图控制器中的另一个scrollView没有这个问题。我已经想破了头,但还没有找到原因。 - alexey.metelkin

7

我开始发现这个问题出现在iOS 11上,当我有一个scrollview里包含了另一个scroll view。花费了我将近一天的时间才找到解决方法。

尝试设置内容插入调整行为:

if #available(iOS 11.0, *) {
    scrollView.contentInsetAdjustmentBehavior = .never
}

这个解决了我的collectionview在移动到包含滚动视图的安全区域之外时,将其内容插入向下的一小部分的问题。

1
let oldContentSizeHeight: CGFloat = self.colName.contentSize.height
        self.colName.reloadData()
        self.colName.layoutIfNeeded()
        self.view.layoutIfNeeded()
        self.colName.contentOffset.y = self.colName.contentOffset.y + (self.colName.contentSize.height - oldContentSizeHeight)

0

这是正确答案的Swift 4.2版本,但为了使其可行,您必须添加协议UIScrollViewDelegate

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if self.collectionView.contentOffset.y < 0 {
        self.collectionView.contentOffset = CGPoint(x: self.collectionView.contentOffset.x, y: 0.0)
    }
}

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