68 votes

Comment faire en sorte que les vues supplémentaires flottent dans UICollectionView comme le font les en-têtes de section dans UITableView en style simple ?

J'ai du mal à obtenir un effet d'"en-tête de section flottant" avec UICollectionView . Quelque chose qui a été assez facile dans UITableView (comportement par défaut pour UITableViewStylePlain ) semble impossible dans UICollectionView sans beaucoup de travail. Est-ce que je rate l'évidence ?

Apple ne fournit aucune documentation sur la manière d'y parvenir. Il semble que l'on doive sous-classer UICollectionViewLayout et mettre en place une mise en page personnalisée juste pour obtenir cet effet. Cela représente un travail considérable, avec la mise en œuvre des méthodes suivantes :

Méthodes à remplacer

Chaque objet de mise en page doit mettre en œuvre les méthodes suivantes :

collectionViewContentSize
layoutAttributesForElementsInRect:
layoutAttributesForItemAtIndexPath:
layoutAttributesForSupplementaryViewOfKind:atIndexPath: (if your layout supports supplementary views)
layoutAttributesForDecorationViewOfKind:atIndexPath: (if your layout supports decoration views)
shouldInvalidateLayoutForBoundsChange:

Cependant, je ne sais pas comment faire pour que la vue supplémentaire flotte au-dessus des cellules et "reste" en haut de la vue jusqu'à ce que la section suivante soit atteinte. Existe-t-il un indicateur à cet effet dans les attributs de mise en page ?

J'aurais utilisé UITableView mais j'ai besoin de créer une hiérarchie assez complexe de collections qui est facilement réalisable avec une vue de collection.

Tout conseil ou exemple de code serait grandement apprécié !

4voto

Zaid Khan Points 15

Si le schéma d'écoulement est déjà défini dans Storyboard o Xib puis essayez ceci,

(collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionHeadersPinToVisibleBounds = true

3voto

Randy Marsh Points 3229

@iPrabu avait un excellente réponse con sectionHeadersPinToVisibleBounds . J'ajouterai simplement que vous pouvez également définir cette propriété dans Interface Builder :

  1. Sélectionnez l'objet de mise en forme du flux dans le navigateur de documents. (S'il est réduit, développez-le d'abord en utilisant le bouton de la barre d'outils dans le coin inférieur gauche de l'éditeur).

Selecting the flow layout object in the document navigator.

  1. Ouvrez l'inspecteur d'identité et ajoutez un attribut d'exécution défini par l'utilisateur avec un chemin de clé sectionHeadersPinToVisibleBounds , type Booléen et la case à cocher est cochée.

Setting the runtime attribute in the Identity inspector.

L'affichage par défaut de l'en-tête a un arrière-plan transparent. Vous pourriez vouloir le rendre (partiellement) opaque ou ajouter une vue à effet de flou.

2voto

vigorouscoding Points 91

J'ai rencontré le même problème et j'ai trouvé ceci dans les résultats de Google. Tout d'abord, je tiens à remercier cocotutch pour avoir partagé sa solution. Cependant, je voulais que mon UICollectionView soit faire défiler horizontalement et les en-têtes pour coller à la gauche de l'écran, j'ai donc dû modifier un peu la solution.

En gros, j'ai juste changé ça :

        CGFloat headerHeight = CGRectGetHeight(layoutAttributes.frame);
        CGPoint origin = layoutAttributes.frame.origin;
        origin.y = MIN(
                       MAX(
                           contentOffset.y,
                           (CGRectGetMinY(firstCellAttrs.frame) - headerHeight)
                           ),
                       (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight)
                       );

        layoutAttributes.zIndex = 1024;
        layoutAttributes.frame = (CGRect){
            .origin = origin,
            .size = layoutAttributes.frame.size
        };

à ça :

        if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
            CGFloat headerHeight = CGRectGetHeight(layoutAttributes.frame);
            CGPoint origin = layoutAttributes.frame.origin;
            origin.y = MIN(
                           MAX(contentOffset.y, (CGRectGetMinY(firstCellAttrs.frame) - headerHeight)),
                           (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight)
                           );

            layoutAttributes.zIndex = 1024;
            layoutAttributes.frame = (CGRect){
                .origin = origin,
                .size = layoutAttributes.frame.size
            };
        } else {
            CGFloat headerWidth = CGRectGetWidth(layoutAttributes.frame);
            CGPoint origin = layoutAttributes.frame.origin;
            origin.x = MIN(
                           MAX(contentOffset.x, (CGRectGetMinX(firstCellAttrs.frame) - headerWidth)),
                           (CGRectGetMaxX(lastCellAttrs.frame) - headerWidth)
                           );

            layoutAttributes.zIndex = 1024;
            layoutAttributes.frame = (CGRect){
                .origin = origin,
                .size = layoutAttributes.frame.size
            };
        }

Ver: https://gist.github.com/vigorouscoding/5155703 o http://www.vigorouscoding.com/2013/03/uicollectionview-with-sticky-headers/

2voto

Je l'ai fait avec codage vigoureux Le code de l'entreprise. Cependant, ce code n'a pas pris en compte la sectionInset.

J'ai donc modifié ce code pour le défilement vertical

origin.y = MIN(
              MAX(contentOffset.y, (CGRectGetMinY(firstCellAttrs.frame) - headerHeight)),
              (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight)
           );

à

origin.y = MIN(
           MAX(contentOffset.y, (CGRectGetMinY(firstCellAttrs.frame) - headerHeight - self.sectionInset.top)),
           (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight + self.sectionInset.bottom)
           );

Si vous voulez du code pour le défilement horizontal, référez-vous au code ci-dessus.

2voto

TimBigDev Points 103

Swift 5.0

Mettez ce qui suit dans votre viewDidLoad :

if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
    layout.sectionHeadersPinToVisibleBounds = true
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X