iOS 10/11 UICollectionViewFlowLayout使用UICollectionViewFlowLayoutAutomaticSize会导致页脚辅助视图未对齐

iOS 10/11 UICollectionViewFlowLayout使用UICollectionViewFlowLayoutAutomaticSize会导致页脚辅助视图未对齐,ios,uicollectionview,uicollectionviewlayout,Ios,Uicollectionview,Uicollectionviewlayout,因此,这是一个有趣的问题,我们在iOS 10上发现了UICollectionViewFlowLayout(在iOS 11上仍然是一个问题),并将UICollectionViewFlowLayoutAutomaticSize用于EstimatedItemize 我们发现,对estimatedItemSize使用UICollectionViewFlowLayoutAutomaticSize会导致页脚补充视图浮动在底部的几个单元格上方(红色/粉色为页眉,绿色为页脚) 以下是示例应用程序的VC代码:

因此,这是一个有趣的问题,我们在iOS 10上发现了
UICollectionViewFlowLayout
(在iOS 11上仍然是一个问题),并将
UICollectionViewFlowLayoutAutomaticSize
用于EstimatedItemize

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

以下是示例应用程序的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功能时是否存在错误,或者我是否错误地使用了它

向苹果提交的bug ID为:28843116

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


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

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


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

UICollectionViewFlowLayout
非常支持单元格的自动布局,但它不支持补充视图的自动布局。每当自动布局代码更新单元格的框架时,它对页眉和页脚不做任何操作。所以您需要告诉布局,它应该使页眉和页脚无效。这是有办法的

您应该重写
UICollectionViewLayout
func无效上下文(对于PreferredLayoutAttribute:UICollectionViewLayoutAttribute,带有OriginalAttribute:UICollectionViewLayoutAttribute)
,并在其中执行补充视图无效

例如:

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
提供的无效上下文使标题补充视图无效。您也可以将此方法用于页脚无效。

您需要提供estimatedItemSize afaik。这不是Optionality设置的问题,只是iOS 10和之前的版本有所不同。你找到解决方案了吗?没有,我向苹果公司提交了一个bug,但他们没有关闭它或将其标记为重复,因此基于此,我假设它是流布局中的一个实际bug。谢谢你的输入。虽然如果您查看我发布的代码,我正在使用
referenceSizeForFooterInSection
referenceSizeForFooterInSection
委托方法将高度设置为90分。或者你指的是别的什么?代码很好。移除此部分并尝试使用计算给出单元格的大小<代码>如果#可用(iOS 10.0,*){layout.estimatedItemSize=UICollectionViewFlowLayoutAutomaticSize}其他{layout.estimatedItemSize=CGSize(宽度:self.collectionView.bounds.width,height:50)}如果我不使用
UICollectionViewFlowLayoutAutomaticSize,它会工作,但问题的关键在于理解
UICollectionViewFlowLayoutAutomaticSize
是如何工作的。我们的解决方案最终移动了自动调整大小,就像您的建议一样,但将来使用自动调整大小还是不错的。您应该将其用于没有补充视图的集合视图。我没有任何文档,但根据我的经验,它只返回单元格的正确大小。它不计算辅助视图的大小和偏移量。这很奇怪,当你调试所有东西并查看生成的偏移量时,它们实际上看起来是正确的。只有当视图被定位时,奇怪的事情才会发生。我已经查阅了很多文档,试图找出这个问题,但是文档中没有任何地方说您不应该在补充视图中使用
UICollectionViewFlowLayoutAutomaticSize
。因此,我认为这是UIKit中的一个bug。与其说是“不应该”使用它,不如说是“不能”使用它;)这为我解决了问题。突然,我的标题视图被正确定位。在我的原因中,我需要通过调用
context.invalidateItems(at:)
,使单元格本身以及
if
范围内的单元格无效。看起来在iOS12中,没有必要使辅助元素无效,因为它们已经被布局好了