web-dev-qa-db-fra.com

iOS 10/11 UICollectionViewFlowLayout utilisant UICollectionViewFlowLayoutAutomaticSize entraîne une vue supplémentaire du pied de page mal alignée

C'est donc un problème intéressant que nous avons trouvé avec UICollectionViewFlowLayout sur iOS 10 (toujours un problème sur 11) et en utilisant UICollectionViewFlowLayoutAutomaticSize pour leItemSize estimé.

Nous avons constaté que l'utilisation de UICollectionViewFlowLayoutAutomaticSize pour l'estimationItemSize entraîne la vue supplémentaire du pied de page flottant au-dessus des quelques cellules du bas (rouge/rose est l'en-tête, vert est le pied de page).

UICollectionViewFlowLayoutAutomaticSize problementer image description here

Voici le code VC d'un exemple d'application:

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 {

}

Quelqu'un a-t-il réussi à faire fonctionner UICollectionViewFlowLayoutAutomaticSize sur iOS 10 avec des vues supplémentaires d'en-tête et de pied de page? Si j'ajoute une taille à l'estimationItemSize, cela semble fonctionner, mais je veux savoir s'il y a un bogue dans l'utilisation de la nouvelle fonctionnalité iOS 10 ou si je l'utilise incorrectement.

Le bogue déposé avec Apple a l'ID: 28843116

[~ # ~] mise à jour [~ # ~] : cela semble toujours être un problème sur 10.3 Beta 1

MISE À JOUR 2 : Cela semble toujours être un problème dans iOS 11 Beta 1

23
dlbuckley

UICollectionViewFlowLayout prend très bien en charge la disposition automatique des cellules, MAIS il ne la prend pas en charge pour les vues supplémentaires. Chaque fois que le code de disposition automatique met à jour le cadre de la cellule, il ne fait rien avec les en-têtes et les pieds de page. Vous devez donc indiquer à la mise en page qu'elle doit invalider les en-têtes et les pieds de page. Et il y a une méthode pour ça!

Vous devez remplacer la func invalidationContext(forPreferredLayoutAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes: UICollectionViewLayoutAttributes) de UICollectionViewLayout et y effectuer une invalidation de vue supplémentaire.

Exemple:

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
}

Dans l'exemple ci-dessus, j'utilise le contexte d'invalidation fourni par UICollectionViewFlowLayout pour invalider la vue supplémentaire d'en-tête si la première cellule de la section a été invalidée. Vous pouvez également utiliser cette méthode pour l'invalidation du pied de page.

24
Anton Lagutin

J'ai rencontré le même problème. UICollectionViewFlowLayoutAutomaticSize ne fonctionne pas pour les vues supplémentaires. Utilisez le UICollectionViewDelegateFlowLayout pour donner la taille explicitement. Il est préférable de calculer les tailles et d'utiliser les délégués car les calculs de taille automatiques provoquent parfois un retard.

utilisez les méthodes déléguées referenceSizeForHeaderInSection et referenceSizeForFooterInSection pour donner explicitement la taille de l'en-tête et du pied de page.

1
Ashutosh Pandey