web-dev-qa-db-fra.com

Comment ajouter une vue d'en-tête dans UICollectionView comme UITableView tableHeaderView

Comment puis-je ajouter une vue d'en-tête/vue de dessus (pas un en-tête de section) en haut d'un UICollectionView?

Elle doit agir exactement comme la propriété UITableView de tableHeaderView.

Il doit donc s'asseoir au-dessus de la première vue d'en-tête de section (avant la section à l'index 0), faire défiler le reste du contenu et interagir avec l'utilisateur.

Le meilleur que j'ai trouvé jusqu'à présent est de créer un XIB spécial (avec MyCollectionReusableView sous-classe de UICollectionReusableView en tant que propriétaire du fichier) pour la première vue d'en-tête de section qui est assez grande pour contenir également mes sous-vues dans l'en-tête, c'est une sorte de hack, je pense, et je n'ai pas réussi à détecter les touches.

Je ne sais pas si je peux créer ma sous-classe MyCollectionReusableView pour autoriser les contacts ou il existe une meilleure méthode.

37
ChrHansen

J'ai mis une vue en haut d'une vue de collection en ajoutant simplement un UIView comme sous-vue de la vue de collection. Il fait défiler vers le haut avec la vue de la collection et il a une interaction utilisateur UIView normale. Cela fonctionne bien si vous n'avez pas d'en-tête de section, mais ne fonctionne pas si vous en avez. Dans cette situation, je ne vois rien de mal à la façon dont vous le faites. Je ne sais pas pourquoi vous ne détectez pas les contacts, ils fonctionnent bien pour moi.

7
rdelmar
self.collectionView  =  [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 320, self.view.frame.size.height) collectionViewLayout:flowlayout];
self.collectionView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0);
UIImageView *imagev = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"015.png"]];
imagev.frame = CGRectMake(0, -50, 320, 50);
[self.collectionView addSubview: imagev];
[self.view addSubview: _collectionView];

J'utilise l'attribut contentInset pour insérer un cadre en haut du UICollectionView, puis j'y ajoute la vue image, et cela réussit. Je pense qu'il peut agir exactement comme la propriété UITableView de tableHeaderView. Qu'est-ce que tu penses?

56
dxci

La meilleure façon d'y parvenir est de créer un en-tête de section pour la première section. Définissez ensuite la propriété UICollectionViewFlowLayout:

@property(nonatomic) BOOL sectionHeadersPinToVisibleBounds

ou Swift

var sectionHeadersPinToVisibleBounds: Bool

à NON (faux pour Swift). Cela garantira que l'en-tête de section défile en continu avec les cellules et ne sera pas épinglé en haut comme le ferait normalement un en-tête de section.

2
Scott Kaiser

Je pense que la meilleure façon d'accomplir cela est de sous-classer UICollectionViewLayout (UICollectionViewFlowLayout) et d'ajouter les attributs d'en-tête ou de pied de page nécessaires.

Étant donné que tous les éléments, y compris la vue supplémentaire dans la disposition UICollectionView en fonction de sa propriété collectionViewLayout, c'est le collectionviewlayout qui décide s'il existe un en-tête (pied de page) ou non.

Utiliser contentInset est plus facile, mais il peut y avoir un problème lorsque vous souhaitez masquer ou afficher l'en-tête dynamiquement.

J'ai écrit un protocole pour y parvenir, qui pourrait être adopté par n'importe quelle sous-classe de UICollectionViewLayout pour lui donner un en-tête ou un pied de page. Vous pouvez le trouver ici.

L'idée principale est de créer un UICollectionViewLayoutAttributes pour l'en-tête et de le renvoyer dans layoutAttributesForElements(in rect: CGRect) si nécessaire, vous devrez modifier tous les autres attributs, tous leurs emplacements doivent être déplacés vers le bas par en-tête hauteur parce que l'en-tête est au-dessus d'eux tous.

1
Billthas

J'ai fini par utiliser une extension UICollectionView pour ajouter mon en-tête personnalisé. En utilisant une balise spécifique, je suis capable de simuler la propriété stockée pour identifier mon en-tête personnalisé (tout transparent de l'extérieur). Vous devrez peut-être faire défiler jusqu'à un décalage spécifique si la disposition de l'UICollectionView n'est pas terminée lorsque vous ajoutez votre en-tête personnalisé.

extension UICollectionView {
    var currentCustomHeaderView: UIView? {
        return self.viewWithTag(CustomCollectionViewHeaderTag)
    }

    func asssignCustomHeaderView(headerView: UIView, sideMarginInsets: CGFloat = 0) {
        guard self.viewWithTag(CustomCollectionViewHeaderTag) == nil else {
            return
        }
        let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
        headerView.frame = CGRect(x: sideMarginInsets, y: -height + self.contentInset.top, width: self.frame.width - (2 * sideMarginInsets), height: height)
        headerView.tag = CustomCollectionViewHeaderTag
        self.addSubview(headerView)
        self.contentInset = UIEdgeInsets(top: height, left: self.contentInset.left, bottom: self.contentInset.bottom, right: self.contentInset.right)
    }

    func removeCustomHeaderView() {
        if let customHeaderView = self.viewWithTag(CustomCollectionViewHeaderTag) {
            let headerHeight = customHeaderView.frame.height
            customHeaderView.removeFromSuperview()
            self.contentInset = UIEdgeInsets(top: self.contentInset.top - headerHeight, left: self.contentInset.left, bottom: self.contentInset.bottom, right: self.contentInset.right)
        } 
    }
}

CustomCollectionViewHeaderTag fait référence au numéro de balise que vous donnez à votre en-tête. Assurez-vous qu'il ne s'agit pas de la balise d'une autre vue intégrée à votre UICollectionView.

1
Swift Rabbit