使用UICollectionViewFlowLayoutAutomaticSize的iOS 10/11 UICollectionViewFlowLayout导致页脚补充视图未对齐

dlb*_*ley 23 ios uicollectionview uicollectionviewlayout

所以这是我们UICollectionViewFlowLayout在iOS 10上发现的一个有趣的问题(仍然是11的问题)并UICollectionViewFlowLayoutAutomaticSize用于estimateItemSize.

我们发现使用UICollectionViewFlowLayoutAutomaticSizeestimatedItemSize导致页脚补充视图浮动在底部的几个单元格之上.(红色/粉红色是标题,绿色是页脚.)

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 {

}
Run Code Online (Sandbox Code Playgroud)

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

向Apple提交的错误ID为:28843116

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

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

小智 24

UICollectionViewFlowLayout支持单元格的自动布局,它不支持补充视图.每次自动布局代码更新单元格的框架时,它都不会对页眉和页脚执行任何操作.因此,您需要告诉布局它应该使页眉和页脚无效.并且有一种方法可以做到这一点!

你应该覆盖UICollectionViewLayout's func 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
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这解决了我的问题.突然我的标题视图被正确定位. (2认同)

Ash*_*dey 1

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

使用referenceSizeForHeaderInSectionreferenceSizeForFooterInSection委托方法显式指定页眉和页脚大小。