Je bidouille les nouvelles classes UICollectionView et UICollectionViewLayout. J'ai créé une présentation personnalisée, en sous-classant UICollectionViewFlowLayout.
La taille de mes cellules change de façon dynamique et je règle la taille des éléments à l'aide de la méthode de délégation ci-dessous
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
return CGSizeMake(80, 80);
}
Maintenant, sous la méthode prepareLayout de ma classe UICollectionViewFlowLayout personnalisée, je dois accéder à ces variables de taille afin de pouvoir calculer comment les placer et les mettre en cache pour layoutAttributesForItemAtIndexPath.
Cependant, il semble impossible de trouver une propriété sous UICollectionView ou UICollectionViewFlowLayout pour atteindre les tailles d'élément personnalisé que j'ai définies dans la méthode delegate.
Je l'ai trouvé moi-même.
Implémenter la classe personnalisée comme sans omettre UICollectionViewDelegateFlowLayout
@interface SECollectionViewCustomLayout : UICollectionViewFlowLayout
<UICollectionViewDelegateFlowLayout>
et alors vous pouvez appeler
CGSize size = [self collectionView:self.collectionView
layout:self
sizeForItemAtIndexPath:indexPath];
En regardant les différents fichiers d'en-tête UICollectionView...
et en regardant la vidéo WWDC 2012 Session 219 - Vues de collection avancées et création de présentations personnalisées (à partir de 6h50 environ), il semble que le modèle de délégué extensible tire parti de la frappe dynamique pour assurer la mise en page peut accéder correctement à ses méthodes de délégué étendu.
UI(Collection)ViewController
qui gère la vue de collection) doit se déclarer lui-même pour la prise en charge de ce protocole personnalisé. UICollectionViewFlowLayout
ou une sous-classe de celle-ci, cela signifie simplement que vous déclarez la conformité à UICollectionViewDelegateFlowLayout
..m
si vous préférez ne pas #import
l'en-tête de présentation dans l'interface du délégué.collectionView
de la présentation et convertissez le délégué en un objet conforme au protocole requis pour convaincre le compilateur.respondsToSelector:
est comme d'habitude avant d'appeler des méthodes de délégué facultatives. En fait, si vous le souhaitez, il n'y a pas de mal à le faire pour toutes les méthodes, car le transtypage signifie qu'il n'y a pas de garantie d'exécution au délégué implémentera même les méthodes requises.Donc, si vous implémentez une mise en page personnalisée nécessitant un délégué pour certaines de ses informations, votre en-tête pourrait ressembler à ceci:
@protocol CollectionViewDelegateCustomLayout <UICollectionViewDelegate>
- (BOOL)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)layout
shouldDoSomethingMindblowingAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface CustomLayout : UICollectionViewLayout
// ...
@end
Votre délégué déclare la conformité (je l’ai déjà fait dans le fichier d’application):
#import "CustomLayout.h"
@interface MyCollectionViewController () <CollectionViewDelegateCustomLayout>
@end
@implementation
// ...
- (BOOL)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)layout
shouldDoSomethingMindblowingAtIndexPath:(NSIndexPath *)indexPath
{
return [self canDoSomethingMindblowing];
}
// ...
@end
Et dans l'implémentation de votre mise en page, vous accédez à la méthode comme ceci:
BOOL blowMind;
if ([self.collectionView.delegate respondsToSelector:@selecor(collectionView:layout:shouldDoSomethingMindblowingAtIndexPath:)]) {
blowMind = [(id<CollectionViewDelegateCustomLayout>)self.collectionView.delegate collectionView:self.collectionView
layout:self
shouldDoSomethingMindblowingAtIndexPath:indexPath];
} else {
// Perhaps the layout also has a property for this, if the delegate
// doesn't support dynamic layout properties...?
// blowMind = self.blowMind;
}
Notez qu'il est sans danger de transtyper ici, car nous vérifions de toute façon que le délégué répond à cette méthode au préalable.
Ce n'est que spéculation, mais je suppose que c'est la façon dont Apple gère le protocole UICollectionViewDelegateFlowLayout
.
delegate
dans la présentation du flux, les appels doivent donc passer par le délégué de la vue de collection.UICollectionViewController
ne se conforme pas publiquement au délégué de disposition de flux étendu (et je doute que ce soit le cas dans un autre en-tête privé).UICollectionView
's delegate
La propriété déclare uniquement la conformité au protocole' base 'UICollectionViewDelegate
. Encore une fois, je doute qu’une sous-classe/catégorie privée de UICollectionView
soit utilisée par la structure de flux pour éviter le recours à la conversion de type. Pour ajouter du poids à ce point, Apple déconseille de sous-classer UICollectionView
dans la documentation (Guide de programmation Collection View pour iOS: Création de présentations personnalisées ):Évitez de sous-classer UICollectionView. La vue Collection a peu ou pas d’apparence. Au lieu de cela, il extrait toutes ses vues de votre objet de source de données et toutes les informations relatives à la présentation de l'objet de présentation.
Alors on y va. Pas compliqué, mais vaut la peine de savoir comment le faire de manière à respecter les paradigmes.
Il existe une version Swift:
self.collectionView(self.collectionView, layout: self.collectionView.collectionViewLayout, sizeForItemAtIndexPath: indexPath)
Consultez UICollectionView-FlowLayout sur GitHub. Même idée, cela facilite l'accès aux méthodes de délégation étendues de flowLayout.
Dans mon cas, tout ce qui concerne la disposition, la disposition des cellules, etc. est défini dans nib pour UIViewController et nib distinct pour UICollectionViewCell. MyCollectionViewCell
contient UIImageView
avec autolayout à la cellule avec remplissage/marges mais de forme carrée.
J'ai besoin d'icônes rondes à la place mais je ne veux pas prendre en compte la pointe que j'utilise pour iPhone ou pour iPad (j'ai des plumes séparées pour les appareils et pour l'orientation).
Je ne souhaite pas implémenter @selector(collectionView:layout:sizeForItemAtIndexPath:)
dans mon contrôleur de vue.
Donc, dans collectionView:cellForItemAtIndexPath:
, Je peux simplement utiliser
CGSize size = cell.imageView.bounds.size;
cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerRadius = size.height/2.0;
Parce que collectionView:layout:sizeForItemAtIndexPath:
appelle avant collectionView:cellForItemAtIndexPath:
et que la mise en page soit terminée.
Vous pouvez vérifier les avatars ronds en bas
Pour les lecteurs ultérieurs, IOS 7 a été défini par UICollectionViewFlowLayout.