【问题标题】:iOS 10/11 UICollectionViewFlowLayout using UICollectionViewFlowLayoutAutomaticSize results in footer supplementary view misalignediOS 10/11 UICollectionViewFlowLayout 使用 UICollectionViewFlowLayoutAutomaticSize 导致页脚补充视图未对齐
【发布时间】:2017-02-28 23:12:37
【问题描述】:

所以这是我们在 iOS 10 上使用 UICollectionViewFlowLayout 发现的一个有趣的问题(在 11 上仍然是一个问题),并使用 UICollectionViewFlowLayoutAutomaticSize 作为估计的ItemSize。

我们发现使用UICollectionViewFlowLayoutAutomaticSize 作为estimatedItemSize 会导致页脚补充视图漂浮在底部几个单元格上方。(红色/粉红色是页眉,绿色是页脚。)

这是一个示例应用的 VC 代码:

import UIKit

class ViewController: UIViewController {

    // MARK: Properties

    let texts: [String] = [
        "This is some text",
        "This is some more text",
        "This is even more text"
    ]

    // MARK: Outlets

    @IBOutlet var collectionView: UICollectionView! {
        didSet {
            self.collectionView.backgroundColor = .orange
        }
    }

    // MARK: Lifecycle

    override func viewDidLoad() {

        super.viewDidLoad()

        // Layout
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        if #available(iOS 10.0, *) {
            layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
        } else {
            layout.estimatedItemSize = CGSize(width: self.collectionView.bounds.width, height: 50)
        }
        self.collectionView.collectionViewLayout = layout

        // Register Cells
        self.collectionView.register(UINib(nibName: "TextCell", bundle: nil), forCellWithReuseIdentifier: String(describing: TextCell.self))
        self.collectionView.register(UINib(nibName: "SectionHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: String(describing: SectionHeader.self))
        self.collectionView.register(UINib(nibName: "SectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: String(describing: SectionFooter.self))

        self.collectionView.reloadData()
    }
}

// MARK: - UICollectionViewDelegateFlowLayout Methods

extension ViewController: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {

        return CGSize(width: self.collectionView.bounds.width, height: 90)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {

        return CGSize(width: self.collectionView.bounds.width, height: 90)
    }
}

// MARK: - UICollectionViewDataSource Methods

extension ViewController: UICollectionViewDataSource {

    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        return self.texts.count
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: TextCell.self), for: indexPath)

        if let textCell = cell as? TextCell {

            let text = self.texts[indexPath.row]
            textCell.configure(text: text)
        }

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

        switch kind {
        case UICollectionElementKindSectionHeader:

            return collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: String(describing: SectionHeader.self), for: indexPath)

        case UICollectionElementKindSectionFooter:

            return collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: String(describing: SectionFooter.self), for: indexPath)

        default:
            return UICollectionReusableView()
        }
    }
}

// MARK: - UICollectionViewDelegate Methods

extension ViewController: UICollectionViewDelegate {

}

有没有人设法让 UICollectionViewFlowLayoutAutomaticSize 在带有补充页眉和页脚视图的 iOS 10 上工作?如果我为estimatedItemSize 添加一个大小,那么它似乎可以工作,但我想知道在使用新的iOS 10 功能时是否存在错误,或者我是否使用不正确。

向 Apple 提交的错误 ID 为:28843116

更新:这似乎仍然是 10.3 Beta 1 的问题

更新 2:这似乎仍然是 iOS 11 Beta 1 中的一个问题

【问题讨论】:

  • 您需要提供估计的ItemSize afaik。这不是可选的
  • 正在设置中,只是iOS 10和之前版本不同。
  • 您找到解决方案了吗?
  • 不,我向 Apple 提交了一个错误,他们没有关闭它或将其标记为欺骗,因此我假设它是流布局中的一个实际错误。

标签: ios uicollectionview uicollectionviewlayout


【解决方案1】:

我遇到了同样的问题。 UICollectionViewFlowLayoutAutomaticSize 不适用于补充视图。使用UICollectionViewDelegateFlowLayout 明确给出大小。最好计算尺寸并使用委托,因为自动尺寸计算有时会导致滞后。

使用referenceSizeForHeaderInSectionreferenceSizeForFooterInSection 委托方法明确指定页眉和页脚的大小。

【讨论】:

  • 感谢您的意见。尽管如果您查看我发布的代码,我正在使用 referenceSizeForHeaderInSectionreferenceSizeForFooterInSection 委托方法将高度设置为 90pts。还是你指的是别的东西?
  • 代码没问题。删除这部分并尝试使用计算给出单元格的大小。 if #available(iOS 10.0, *) { layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize } else { layout.estimatedItemSize = CGSize(width: self.collectionView.bounds.width, height: 50) }
  • 如果我不使用UICollectionViewFlowLayoutAutomaticSize,它会起作用,但问题的重点是了解UICollectionViewFlowLayoutAutomaticSize 的工作原理。我们的解决方案最终像您的建议一样移动了自动调整大小,但是将来使用自动调整大小仍然会很好。
  • 您应该将它与没有补充视图的集合视图一起使用。我没有任何文档,但据我所知,它只返回正确的单元格大小。它不计算补充视图的大小和偏移量。
  • 看到这很奇怪,当您调试所有内容并查看产生的偏移量时,它们实际上看起来是正确的。只有当视图被定位时,才会发生奇怪的事情。我已经浏览了很多次试图找出这个问题的文档,但它并没有说你不应该在任何地方使用 UICollectionViewFlowLayoutAutomaticSize 和补充视图。因此,我相信这是 UIKit 中的一个错误。与其说是“不应该”使用它,不如说是“不能”使用它;)
【解决方案2】:

UICollectionViewFlowLayout 很好地支持单元格的自动布局,但是它不支持补充视图。每次自动布局代码更新单元格的框架时,它对页眉和页脚都不做任何事情。所以你需要告诉布局它应该使页眉和页脚无效。并且有一个方法!

您应该覆盖UICollectionViewLayoutfunc invalidationContext(forPreferredLayoutAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes: UICollectionViewLayoutAttributes) 并在其中执行补充视图失效。

例子:

override open func invalidationContext(forPreferredLayoutAttributes preferred: UICollectionViewLayoutAttributes,
        withOriginalAttributes original: UICollectionViewLayoutAttributes)
                -> UICollectionViewLayoutInvalidationContext {
    let context: UICollectionViewLayoutInvalidationContext = super.invalidationContext(
            forPreferredLayoutAttributes: preferred,
            withOriginalAttributes: original
    )

    let indexPath = preferred.indexPath

    if indexPath.item == 0 {
        context.invalidateSupplementaryElements(ofKind: UICollectionElementKindSectionHeader, at: [indexPath])
    }

    return context
}

在上面的示例中,如果部分中的第一个单元格无效,我将使用 UICollectionViewFlowLayout 提供的无效上下文来使标题补充视图无效。您也可以使用此方法进行页脚失效。

【讨论】:

  • 这已经解决了我的问题。突然我的标题视图被正确定位了。
  • 在我的事业中,我需要通过调用 context.invalidateItems(at:) 使单元格本身在 if 范围内无效。
  • 看起来在 iOS12 中没有必要使补充元素无效,因为它们的布局很好
猜你喜欢
  • 1970-01-01
  • 2013-05-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-26
  • 2017-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多