web-dev-qa-db-fra.com

UICollectionView Multiple Sections and Headers

Je ne parviens pas à essayer de créer plusieurs sections dans la vue Collection avec un en-tête pour chaque section. Je ne connais pas Obj-C et j'ai trouvé une bonne quantité de tutoriels, mais je n'ai pas encore trouvé comment le convertir en Swift. 

Toutes mes données sont statiques et tout ce dont j'ai besoin est une sorte de tableau ou de dictionnaire que je peux utiliser pour créer plusieurs sections. J'ai déjà une vue de collection avec 1 section qui fonctionne, donc si vous avez un aperçu ou un code pour plusieurs sections, ce serait utile. 

Je sais comment définir plusieurs sections à l'aide de 

func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int   {
    return sectionData.count
}

Je pense que la principale chose pour laquelle j’ai besoin d’aide est d’implémenter cette fonction.

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { }

et mettre en place les données! 

UICollectionView et UITableView sont presque exactement identiques, donc si vous savez faire plusieurs sections dans un UITableView dans Swift, votre aide est également appréciée.

13
user3399235

La fonction cellForItemAtIndexPath gère le remplissage de chaque section avec des cellules, elle ne gère pas les sections ni les vues supplémentaires et ne constitue donc pas l'élément principal pour lequel vous avez besoin d'aide pour créer des en-têtes de section. 

la méthode que vous devez implémenter est viewForSupplementaryElementOfKind. Sa signature est: 

func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {}

En supposant que votre collectionView fonctionne correctement pour 1 section (vous avez correctement rempli le corps de votre cellForItemAtIndexPath et votre tableau sectionData reflète correctement le nombre de sections que vous souhaitez afficher), vous devriez pouvoir implémenter les en-têtes de section à l'aide des pointeurs suivants: 

Avec les cellules, UICollectionView prend également en charge les objets de vue "supplémentaires", généralement utilisés pour les en-têtes ou les pieds de page. Ces vues supplémentaires fonctionnent de manière très similaire aux objets UICollectionViewCell. De la même manière que cellForItemAtIndexPath traite les cellules, la fonction viewForSupplementaryElementOfKind gère les vues supplémentaires. 

Pour l'implémenter, vous devez d'abord préparer votre ViewController. Commencez par modifier votre objet de présentation afin de refléter une taille d'en-tête appropriée, à laquelle chaque en-tête adhère:

 let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
 layout.headerReferenceSize = CGSize(width: self.view.frame.size.width, height: 30)

REMARQUE: j'utilise UICollectionViewFlowLayout.

Ensuite, si vous ne l'avez pas déjà fait, créez une classe SectionHeader qui définit chaque objet d'en-tête de section afin de pouvoir ensuite inscrire cette classe avec votre objet collectionView comme suit:

  collectionView!.registerClass(SectionHeaderView.self, forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: "SectionHeaderView");

Ici, les premier et troisième arguments transmis sont identiques à ceux d'un enregistrement de classe UICollectionViewCell, le premier argument de cette méthode est la référence à la classe d'en-tête de section que vous avez créée. Le troisième est l'identifiant de réutilisation pour la vue supplémentaire. 

Le deuxième argument est spécifique aux vues supplémentaires, cela définit le type kind de la vue supplémentaire, qui dans ce cas est un en-tête, la chaîne de constante fournie par la classe UICollectionViewFlowLayout UICollectionElementKindSectionHeader est utilisée pour cela. Si vous avez remarqué les paramètres de la viewForSupplementaryElementOfKind, ce kind est ensuite passé en tant que paramètre kind: String

Remplissez le corps de votre viewForSupplementaryElementOfKind de la même manière que vous le feriez pour une fonction cellForItemAtIndexPath - Utilisation de la méthode dequeueReusableSupplementaryViewOfKind pour créer un objet SectionHeader, puis définissez tous les attributs nécessaires (libellés, couleurs, etc.) et renvoyez enfin l'objet en-tête. 

J'espère que cela t'aides!!

Points de référence: 

https://developer.Apple.com/library/prerelease/ios/documentation/UIKit/Reference/UICollectionViewDataSource_protocol/index.html#//Apple_ref/occ/intfm/UICollectionViewDataSource/

https://developer.Apple.com/library/ios/documentation/UIKit/Reference/UICollectionViewFlowLayout_class/index.html#//Apple_ref/c/data/UICollectionElementKindSectionHeade

14
mkncode

Voici le code qui a fonctionné pour moi

créer la cellule d'en-tête. Pour ce faire, j'ai créé une classe de cellule personnalisée et une nib pour effectuer la personnalisation de la cellule dans l'éditeur graphique.

Dans viewDidLoad, ajoutez ce qui suit

self.collectionView?.registerNib(UINib(nibName: "KlosetCollectionHeaderViewCell", bundle: nil), forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderCell")

Ensuite, vous ajoutez la fonction de délégué

override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> KlosetCollectionHeaderViewCell {

    let headerCell = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "HeaderCell", forIndexPath: indexPath) as? KlosetCollectionHeaderViewCell    

    return headerCell!
  }

Cela placera la HeaderCell dans la vue en coupe de PFCollectionView Les contrôles affichés dans la cellule que vous les ajoutez au fichier xib, ainsi que les prises et les actions

4
lguerra10

Après avoir créé et enregistré un en-tête personnalisé (et/ou des pieds de page), vous pouvez facilement spécifier un en-tête différent (ou des pieds de page pour cette question) pour une section différente. Voici un exemple:

    override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        switch kind {
        case UICollectionElementKindSectionHeader:
            let section = indexPath.section

            switch section {
            case 0:
                let userHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: homeHeaderReuseIdentifier, for: indexPath) as! UserHeader
                return userHeader
            default:
                let postHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: sectionSpacingHeaderReuseIdentifier, for: indexPath) as! PostHeader
                return postHeader
            }
        case UICollectionElementKindSectionFooter:
            let userFooter = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: homeFooterReuseIdentifier, for: indexPath) as! UserFooter
            return userFooter
        default:
            return UICollectionReusableView()
        }
    }

Assurez-vous également de spécifier le nombre correct de sections:

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }
2
sean

Définissez votre UICollectionViewCell qui sera votre vue d'en-tête de type UICollectionElementKindSectionHeader - Dans mon cas, j'ai deux en-têtes - OfferHeaderCell et APRHeaderCell définis comme suit:

verticalCollectionView.register(UINib(nibName: "OfferHeaderCell", bundle: nil), forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: "OfferHeaderCell")
verticalCollectionView.register(UINib(nibName: "APRHeaderCell", bundle: nil), forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: "APRHeaderCell")

Allez-y et renvoyez un en-tête pour chaque section, puis définissez la taille de l'en-tête de section sur zéro dans cette fonction UICollectionViewDelegateFlowLayout.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    if(section==0) {
        return CGSize.zero
    } else if (section==1) {
        return CGSize(width:collectionView.frame.size.width, height:133)
    } else {
        return CGSize(width:collectionView.frame.size.width, height:100)
    }

}

Il est important de définir viewForSupplementaryElementOfKind pour deux sections différentes, comme ci-dessous:

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

    var reusableview = UICollectionReusableView()
    if (kind == UICollectionElementKindSectionHeader) {
        let section = indexPath.section
        switch (section) {
        case 1:
            let  firstheader: OfferHeaderCell = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "OfferHeaderCell", for: indexPath) as! OfferHeaderCell
            reusableview = firstheader
        case 2:
            let  secondHeader: APRHeaderCell = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "APRHeaderCell", for: indexPath) as! APRHeaderCell
            reusableview = secondHeader
        default:
            return reusableview

        }
    }
    return reusableview
}

Et enfin la source de données,

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 3
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    if (section==2) {
        return 2
    }
    return 0
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = verticalCollectionView.dequeueReusableCell(withReuseIdentifier: "ReviseOfferCell", for: indexPath)
    cell.backgroundColor = UIColor.white
    return cell
}

Remarque: N'oubliez pas d'ajouter UICollectionFlowLayout comme ci-dessous:

// MARK: UICollectionViewDelegateFlowLayout

extension MakeAnOfferController: UICollectionViewDelegateFlowLayout {

        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

            if indexPath.item == 0 {
                return CGSize(width: self.view.frame.size.width, height: 626.0)
            }
            return CGSize()
        }

        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {

            if(section==0) {
                return CGSize.zero
            } else if (section==1) {
                return CGSize(width:collectionView.frame.size.width, height:133)
            } else {
                return CGSize(width:collectionView.frame.size.width, height:100)
            }
        }
    }
1
Tarun

La réponse de @ Tarun a fonctionné un festin pour moi; Il me manquait collectionView(_:layout:referenceSizeForHeaderInSection:), ce dont j'avais besoin, car parfois les données à afficher étaient triées et parfois non.

En outre, l'épinglage de l'en-tête de la section en haut de l'écran (comme dans l'affichage du tableau, dans l'application Carnet d'adresses d'Apple) a été réalisé en ajoutant les éléments suivants à viewDidLoad() dans UICollectionViewController:

if let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout {
    flowLayout.sectionHeadersPinToVisibleBounds = true
}
0
Glenn

Solution travaillée pour Swift-3 

i) Créer une cellule personnalisée && xib correspondante

   class SectionHeaderView: UICollectionViewCell {
        static let kReuseIdentifier = "SectionHeaderView"
        @IBOutlet weak var invitationsSectionHeader: UILabel!
        @IBOutlet weak var numberOfPerson: UILabel!
 }

ii) Enregistrer la cellule d'affichage de collection personnalisée pour HeaderView

 self.collectionView.register(UINib(nibName: SectionHeaderView.kReuseIdentifier, bundle: nil), forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: SectionHeaderView.kReuseIdentifier)

iii) Appelez la fonction de délégué pour rendre la vue d'en-tête personnalisée.

  func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        switch kind {
        case UICollectionElementKindSectionHeader:
           let  headerView: SectionHeaderView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: SectionHeaderView.kReuseIdentifier, for: indexPath) as! SectionHeaderView
            return headerView
        default:
            return UICollectionReusableView()
        }
    }

iv) Mention Hauteur de la vue d'en-tête personnalisée

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width:collectionView.frame.size.width, height:30)
}
0
Shrawan