iOS 10/11 UICollectionViewFlowLayout 使用 UICollectionViewFlowLayoutAutomaticSize 导致页脚补充视图未对齐 [英] iOS 10/11 UICollectionViewFlowLayout using UICollectionViewFlowLayoutAutomaticSize results in footer supplementary view misaligned

查看:14
本文介绍了iOS 10/11 UICollectionViewFlowLayout 使用 UICollectionViewFlowLayoutAutomaticSize 导致页脚补充视图未对齐的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So this is an interesting issue we found with UICollectionViewFlowLayout on iOS 10 (still an issue on 11) and using UICollectionViewFlowLayoutAutomaticSize for the estimatedItemSize.

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

We've found that using UICollectionViewFlowLayoutAutomaticSize for the estimatedItemSize results in the footer supplementary view floating above the bottom few cells.(Red/Pink is the header, Green is the footer.)

这是一个示例应用的 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 功能时是否存在错误,或者我是否使用不正确.

Has anyone managed to get UICollectionViewFlowLayoutAutomaticSize to work on iOS 10 with supplementary header and footer views? If I add a size to the estimatedItemSize then it appears to work, but I want to know if there is a bug in using the new iOS 10 feature or if I'm using it incorrectly.

向 Apple 提交的错误 ID 为:28843116

The bug filed with Apple has the ID: 28843116

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

UPDATE: This still appears to be an issue on 10.3 Beta 1

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

UPDATE 2: This still appears to be an issue in iOS 11 Beta 1

推荐答案

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

UICollectionViewFlowLayout supports auto layout for cells very well, BUT it does not supports it for supplementary views. Each time when auto layout code updates cell's frame it does nothing with headers and footers. So you need to tell layout that it should invalidate headers and footers. And there is a method for this!

你应该重写 UICollectionViewLayoutfunc invalidationContext(forPreferredLayoutAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes: UICollectionViewLayoutAttributes) 并在其中执行补充视图失效.

You should override UICollectionViewLayout's func invalidationContext(forPreferredLayoutAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes: UICollectionViewLayoutAttributes) and perform supplementary view invalidation in it.

例子:

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

In example above I am using invalidation context provided by UICollectionViewFlowLayout to invalidate header supplementary view if first cell in section was invalidated. You can use this method for footer invalidation as well.

这篇关于iOS 10/11 UICollectionViewFlowLayout 使用 UICollectionViewFlowLayoutAutomaticSize 导致页脚补充视图未对齐的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆