带有ContentInset的UICollectionView无法完全向下滚动

18

我正在设置UICollectionView的内容插入:

[_collectionView setContentInset:UIEdgeInsetsMake(0.f, 0.f, 100.f, 0.f)];

然后我使用该方法以编程方式滚动到UICollectionView的底部:

- (void)scrollToLastMessageAnimated:(BOOL)animated;
{
    if (_messages.count == 0) { return; }

    NSUInteger indexOfLastSection = _messagesBySections.count - 1;
    NSInteger indexOfMessageInLastSection = [_messagesBySections[indexOfLastSection] count] - 1;
    NSIndexPath *path = [NSIndexPath indexPathForItem:indexOfMessageInLastSection
                                            inSection:indexOfLastSection];

    [_collectionView scrollToItemAtIndexPath:path
                           atScrollPosition:UICollectionViewScrollPositionCenteredVertically
                                   animated:animated];
}

它正在向下滚动,但忽略了contentInset,这意味着最后的单元格在指定的content inset下方:

enter image description here 左边的图像显示了它现在的外观。在右边的图像中,我手动向下滚动到了最后一条消息。

我正在使用AutoLayout,有什么想法是为什么会发生这种情况吗?

编辑:

这里是IB设置的截图: enter image description here


1
你是如何设置底部约束的?这个问题很可能与集合视图的大小有关,而与内容插入量几乎没有什么关系。 - nhgrif
1
拍一张屏幕截图,以了解您所添加的布局。 - E-Riddie
1
我认为你的 _collectionView 高度有问题。你应该将高度设置到屏幕下方的视图。 - Suryakant Sharma
好的,我添加了我的IB设置截图...请见上方... - electronix384128
2
我想在消息滚动到UIToolbar下方时拥有UIToolbar的半透明效果。因此,UICollectionView会位于UIToolBar下方,并设置contentInset。 - electronix384128
6个回答

35

今天,我偶然发现了解决方案!

选择您的视图控制器并取消选中“调整滚动视图插图”的选项。

enter image description here

取消选中此选项后,iOS不会自动调整视图(及其子视图)的插图大小,这对我造成了问题... 取消勾选并通过编程方式配置滚动插图:

- (void)configureInsetsOfCollectionView
{
    [_collectionView setContentInset: UIEdgeInsetsMake(self.navigationController.navigationBar.bounds.size.height + [UIApplication sharedApplication].statusBarFrame.size.height + DEFAULT_SPACING, 0.f, _keyboardHeight + _toolbar.bounds.size.height + DEFAULT_SPACING, 0.f)];
    [_collectionView setScrollIndicatorInsets:UIEdgeInsetsMake(self.navigationController.navigationBar.bounds.size.height + [UIApplication sharedApplication].statusBarFrame.size.height, 0.f, _keyboardHeight + _toolbar.bounds.size.height, 0.f)];
}

我已经花费了数小时在这上面,而我的以前的解决方案最近已经被弃用了,非常感谢! - agrippa
太棒了,完美运作 :D -- 我也相当确定同样适用于UITableView。 - joe

13

如果您使用的是流式布局,请尝试设置_collectionView.collectionViewLayout.sectionInset。


1
这对我很有效。当我有大量的水平contentInsets时,它总是将我滚动到第一个项目。当我将插图放在sectionInset中时,滚动按预期工作。看起来不像是正确的方法,但对我来说有效。 - richkzad
1
谢谢,老兄!节省了我的时间。 - Murat Yasar
1
经过这么多次尝试,这个答案救了我的一天。谢谢老兄。 - atalayasa
但是这个插入将会应用到集合视图的每个部分吗? - Ever Uribe

5

Swift版本

collectionview.contentInset = UIEdgeInsetsMake(44,0,0,0)
collectionview.scrollIndicatorInsets = UIEdgeInsetsMake(44,0,0,0)

这是反过来的,应该是UIEdgeInsets(top: 0, left: 0, 44, right: 0)。 - user1898712

2

可能存在的问题

您将collectionView设置在工具栏下方,并为两个视图都添加了与父视图底部的约束。

解决方案

将工具栏的约束设置为底部、前导,并将宽度和高度设置为固定大小。对于您的collectionView,请将约束设置为顶部,与工具栏相连的底部,前导到父视图以及(备选方案)宽度固定大小。

更新

CollectionView

按照以下步骤进行操作:

检查您的collectionView,不要将其放在工具栏下面,并通过选择Document Outline上的collectionView,在视图上单击ctrl并拖动它,会出现一个弹出窗口,按住shift并选择这些约束。

CollectionView Constraints

Toolbar

通过在视图中使用ctrl拖动来检查前导和底部。并为工具栏添加固定的宽度和高度。

Toolbar Constraints

在viewAppears之前处理滚动

-(void)viewWillAppear:(BOOL)animated
{
    [collectionView reloadData];
    [self scrollToLastMessageAnimated:YES];
}

将工具栏的约束设置为底部、前导,并将宽度和高度设置为固定大小。对于您的collectionView,将约束设置为顶部、与工具栏相接、前导到父视图,并且(可选)宽度固定。 - E-Riddie
你的方法给我带来了相同的行为 :( 而且UIScrollView也不会在UIToolbar下面,缺少半透明效果... - electronix384128
好的,这样做效果更好了!但是有两个问题:1)我的滚动到底部的方法在viewWillAppear:中不再起作用 - 只有在viewDidAppear:中才能使初始滚动到底部(scrollToLastMessageAnimated:)对用户可见,这是不想要的。2)UICollectionView在UIToolBar和键盘后面的半透明效果消失了... - electronix384128
你指的是哪个 scrollView?collectionView 的滚动吗? - E-Riddie
因为正确答案现在已经被标记了!很抱歉,但无论如何还是感谢您的努力... - electronix384128
显示剩余10条评论

2
您可以在您的viewController类中设置referenceSizeForFooterInSection函数:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
    return CGSize(width: view.frame.width, height: 50)
}

只需将高度设置为所需值即可。

0
以编程方式,我使用(Swift 5)解决了这个问题:
collectionView.contentInsetAdjustmentBehavior = .never

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