iPhone X 横向 UICollectionView

UICollectionView in landscape on iPhone X

当iPhone X 横向使用时,您应该检查safeAreaInsets 以在左侧和右侧制作适当大的排水沟。 UITableView 有新的 insetsContentViewsToSafeArea 属性(默认为 true)自动将单元格内容保存在安全区域。

我很惊讶 UICollectionView 似乎没有任何类似的东西。我希望对于垂直滚动的集合视图,在横向时左右两侧将插入到安全区域(相反,如果需要在纵向中,水平滚动的集合视图将被插入)。

确保此行为的最简单方法似乎是添加到集合视图控制器:

- (void)viewSafeAreaInsetsDidChange {
    [super viewSafeAreaInsetsDidChange];
    UIEdgeInsets contentInset = self.collectionView.contentInset;
    contentInset.left = self.view.safeAreaInsets.left;
    contentInset.right = self.view.safeAreaInsets.right;
    self.collectionView.contentInset = contentInset;
}

...假设 contentInset.left/right 通常为零。

(注意:是的,对于 UICollectionViewController,需要 self.view.safeAreaInsets;在调用时,对 safeAreaInsets 的更改奇怪地尚未传播到 self.collectionView )

我错过了什么吗?该样板文件足够简单,但现在对于触及屏幕边缘的 每个 集合视图来说实际上是必需的。 Apple 没有提供默认启用此功能的功能,这似乎真的很奇怪。

UICollectionView 旨在灵活地适应各种布局。最常见的布局是具有多行和多列的网格,但可以使用 UICollectionView.

创建非网格布局 另一方面,

UITableView 是为全角单元格设计的。

因此,UITableView 内置处理安全区域插入的支持是有道理的,因为 table 视图布局将始终受其影响。因为 UICollectionView 使用自定义布局,所以在每次实施的基础上解决这些问题是有意义的,而不是试图提供一种放之四海而皆准的解决方案。

虽然 Nathan 关于 UICollectionView 具有多种布局的多功能性是正确的,但我主要关心 "default" 使用 UICollectionViewFlowLayout 的情况。

原来,iOS11在UICollectionViewFlowLayout上加了一个sectionInsetReference属性。 official documentation 目前缺少描述,但是 headers 将其描述为

The reference boundary that the section insets will be defined as relative to. Defaults to .fromContentInset.

NOTE: Content inset will always be respected at a minimum. For example, if the sectionInsetReference equals .fromSafeArea, but the adjusted content inset is greater that the combination of the safe area and section insets, then section content will be aligned with the content inset instead.

可能的值为

@available(iOS 11.0, *)
public enum UICollectionViewFlowLayoutSectionInsetReference : Int {
    case fromContentInset
    case fromSafeArea
    case fromLayoutMargins
}

并将其设置为 .fromSafeArea 会产生所需的结果,即,当最初处于纵向时:

然后当旋转到横向时,单元格被插入,使它们完全在安全区域内:

...但是,目前存在一个错误,当在 视图处于横向后 旋转回纵向时,它继续表现得好像 left/right safeAreaInsets 设置为横向值:

我已就此问题提交雷达 (rdar://34491993)。

感谢楼上的帮助。对于我的 UICollectionViewController 子类,我将以下内容添加到 viewDidLoad() (Swift 3):

if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
    if #available(iOS 11.0, *) {
        flowLayout.sectionInsetReference = .fromSafeArea
    }
}

有同样的问题。这对我有用:

override func viewDidLoad() {
    if #available(iOS 11.0, *) {
        collectionView?.contentInsetAdjustmentBehavior = .always
    }
}

.always 枚举案例的 documentation 说:

Always include the safe area insets in the content adjustment.

此解决方案在 phone 旋转的情况下也能正常工作。

请记住,上述解决方案无法解决您的 collection 单元格视图(以及受限于其单元格前缘或后缘的子视图)为 full-width 到 collection 查看边界并且未设置为遵守 安全区域布局指南

注意:@petrsyn 的回答使 header 从侧面插入,大多数人可能不希望这样,@Wes Campaigne 的回答对于 full-width 单元格并不能正常工作,其中子视图附加到单元格的前缘或后缘。

必须将 Xib 和 Storyboard 文件设置为 Use Safe Area Layout Guides,然后使用自动布局放置与安全区域或在代码中做类似的事情。

如果您以编程方式将集合视图添加为主视图的子视图 - 那么您可以在 viewDidLoad 方法中执行此操作:

collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)

NSLayoutConstraint.activate([
        collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
        collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
        collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
        collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor)
])