L'appel de setCollectionViewLayout:animation ne recharge pas UICollectionView
Je suis à l'aide d'un UICollectionView avec deux modèles personnalisés qui sont sous-classé de UICollectionViewFlowLayout
Quand ma vue se charge tout d'abord je l'ai mis à une vue par défaut à l'aide de:
[self.collectionView setCollectionViewLayout:self.tableViewLayout];
Ce appels: cellForItemAtIndexPath
- donc pas de problème là. C'est dans viewWillAppear
méthode.
Puis-je utiliser un UIButton pour modifier la mise en page de la vue actuelle de la prochaine mise en page comme ceci:
-(void)changeViewLayoutButtonPressed
{
self.changeLayout = !self.changeLayout;
if (self.changeLayout){
[self.tradeFeedCollectionView setCollectionViewLayout:self.grideLayout animated:YES];
}
else {
[self.tradeFeedCollectionView setCollectionViewLayout:self.tableViewLayout animated:YES];
}
}
Après cet appel - numberOfItemsInSection
est appelé. J'ai vérifié dans le débogueur que le retour de compte n'est pas zéro.
Après cet appel, rien d'autre n'est appelé et mon UICollectionView modifie la mise en page mais depuis cellForItemAtIndexPath
n'est pas nommé - les cellules ne sont pas correctement paramétré.
si j'ai mis [self.collectionView roloadData]
à l'intérieur de numberOfItemsInSection
- alors cellForItemAtIndexPath
est appelé et les cellules sont de l'installation.
Je ne devrais pas besoin de faire un appel manuel de recharger les données dans numberOfItemsInSection
. Quelqu'un peut me dire ce qui se passe?
Modifier
J'ai oublié de mentionner que je suis à l'aide de deux UINibs pour les deux cellules différentes, comme ils ont besoin de légèrement différentes dispositions sont appliquées. Serait-ce un problème?
Merci!
Edit 2
Droite, donc j'ai eu à travailler presque comme je veux. Voici tout le code utilisé pour l'affichage de la collection et comment je modifier ses dispositions.
Les Dispositions Personnalisées
Ce sont des sous-classé de UICollectionViewFlowLayout
- La raison pour laquelle je sous-classé est tout simplement en raison de la face de mon UICollectionView
besoins à l'apparence et au comportement très proche de la Pomme de pré-faites la mise en page. Juste différentes tailles de cellule, cependant.
TableViewLayout
- Pas de code dans le fichier d'en-tête.
- BBTradeFeedTableViewLayout.m
@implementation BBTradeFeedTableViewLayout
-(id)init
{
self = [super init];
if (self){
self.itemSize = CGSizeMake(320, 80);
self.minimumLineSpacing = 0.1f;
}
return self;
}
@end
Gride Disposition
- Pas de code dans le fichier d'en-tête.
- BBTradeFeedGridViewLayout.m
@implementation BBTradeFeedGridViewLayout
-(id)init
{
self = [super init];
if (self){
self.itemSize = CGSizeMake(159, 200);
self.minimumInteritemSpacing = 0.1f;
self.minimumLineSpacing = 0.1f;
}
return self;
}
@end
Puis dans le ViewController
qui a mon UICollectionView
- je déclarer les deux modèles personnalisés comme:
@property (strong, nonatomic) BBTradeFeedTableViewLayout *tableViewLayout;
@property (strong, nonatomic) BBTradeFeedGridViewLayout *grideLayout;
Je puis d'enregistrer les deux .xib fichiers pour le collectionView:
[self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemTableViewCell" bundle:nil] forCellWithReuseIdentifier:@"TableItemCell"];
[self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemGridViewCell" bundle:nil] forCellWithReuseIdentifier:@"GridItemCell"];
Puis, j'ai un UIButton qui modifie la mise en page:
-(void)changeViewLayoutButtonPressed
{
if (!self.gridLayoutActive){
self.gridLayoutActive = YES;
[self.tradeFeedCollectionView setCollectionViewLayout:self.grideLayout animated:YES];
self.lastLayoutUsed = @"GridLayout";
}
else {
self.gridLayoutActive = NO;
[self.tradeFeedCollectionView setCollectionViewLayout:self.tableViewLayout animated:YES];
self.lastLayoutUsed = @"TableLayOut";
}
[self.tradeFeedCollectionView reloadItemsAtIndexPaths:[self.tradeFeedCollectionView indexPathsForVisibleItems]];
}
Enfin - quand un appel de service web se fait - il appelle [self.tradeFeedCollectionView reloadData];
Donc il ma UICollectionView
obtient reloaded et la dernière méthode:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{ static NSString *tableCellIdentifier = @"TableItemCell";
static NSString *gridCellIdentifier = @"GridItemCell";
if (indexPath.item < [self.tradeSearchArray count]){
if (self.gridLayoutActive == NO){
BBItemTableViewCell *tableItemCell = [collectionView dequeueReusableCellWithReuseIdentifier:tableCellIdentifier forIndexPath:indexPath];
if ([self.tradeSearchArray count] > 0){
self.toolBarButtomItem.title = [NSString stringWithFormat:@"%d Results", self.searchResult.searchResults];
tableItemCell.gridView = NO;
tableItemCell.backgroundColor = [UIColor whiteColor];
tableItemCell.item = self.tradeSearchArray[indexPath.row];
}
return tableItemCell;
}else
{
BBItemTableViewCell *gridItemCell= [collectionView dequeueReusableCellWithReuseIdentifier:gridCellIdentifier forIndexPath:indexPath];
if ([self.tradeSearchArray count] > 0){
self.toolBarButtomItem.title = [NSString stringWithFormat:@"%d Results", self.searchResult.searchResults];
gridItemCell.gridView = YES;
gridItemCell.backgroundColor = [UIColor whiteColor];
gridItemCell.item = self.tradeSearchArray[indexPath.row];
}
return gridItemCell;
}
Le problème avec le code ci-dessus
Le code ci-dessus fonctionne. Cependant, les cellules n'animez pas bien, et il semble étrange, presque comme si une actualisation qui s'est passé. Qui est en raison de l'appel:
[self.tradeFeedCollectionView reloadItemsAtIndexPaths:[self.tradeFeedCollectionView indexPathsForVisibleItems]];
Mais c'est la seule façon que je pouvais obtenir pour être proche de ce que je veux.
- Je trouve cette question très longtemps.
- Quoi de mal à cela?
Vous devez vous connecter pour publier un commentaire.
-setCollectionViewLayout:
ou-setCollectionViewLayout:animated:
ne causera pas de vosUICollectionView
recharger ses données.Si vous voulez changer votre style de cellule ou de mettre à jour les données, appel
[self.collectionView reloadData]
etUICollectionViewDataSource
protocole méthodes seront appelées.Si vous souhaitez modifier votre
UICollectionView
la mise en page à une autre, appelez-setCollectionViewLayout:
. Ou si vous voulez mettre à jour votreUICollectionView
mise en page, il suffit d'appeler[self.collectionView.collectionViewLayout invalidateLayout]
.De la cellule de mise en page et les données sont deux choses différentes dans
UICollectionView
.Mise à jour
vous devriez vous débarrasser de toutes les données obsolètes, probablement par
-reloadData
. Et calculer le nouveau cadres de chaque cellule dans votre UICollectionViewLayout sous-classes. Remplacer- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
et- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
.Vous décidez de la nouvelle
contentOffset
. Par exemple, vous pouvez garder le indexPath de certains visible de la cellule et de décider pour faire défiler jusqu'à queindexPath
ousetContentOffset:
à laframe.origin
de la nouvelle cellule dans le mêmeindexPath
après votre mise en page a changé.-(void)changeViewLayoutButtonPressed
?[self.tradeFeedCollectionView reloadItemsAtIndexPaths:[self.tradeFeedCollectionView indexPathsForVisibleItems]]
seulement mettre à jour les données des éléments visibles. La vieille, mal configuré cellules venir Quand vous faites défiler, mais votre mise en page est changé à ce point.-reloadData
mais les choses sont différentes lorsque vous utilisez-reloadItemsAtIndexPaths
?[self.collectionView reloadItemsAtIndexPaths:[self.collectionView indexPathsForVisibleItems]]
. Vos modèles sont différents, le itemSizes sont très variables. Et actuellement visible éléments peuvent être hors de l'écran et les éléments invisibles peut-être venir, en raison de votre mise en page des stratégies. C'est bien que-reloadData
permet de réinitialiser lecontentOffset
. Je pense que c'est une mise en question et il est de votreUICollectionViewLayout
la responsabilité de comprendre la façon de traiter avec lecontentOffset
. Après tout, le précédent est compensée à vide de sens lors de vos données à jour et de la taille de la cellule sont le changement.-reloadData
. Et calculer le nouveau cadres de chaque cellule dans votreUICollectionViewLayout
sous-classes. Remplacer- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
et- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
. Vous décidez de la nouvellecontentOffset
. Par exemple, vous pouvez garder le indexPath de certains visible de la cellule et de décider pour faire défiler jusqu'à que indexPath ousetContentOffset
à laframe.orgin
de la nouvelle cellule dans le même indexPath après votre mise en page a changé.Appelez simplement
reloadData
avant vous passez votre mise en page (laperformBatchUpdates
appel n'est pas obligatoire):Dans Swift:
performBatchUpdates
(en essayant de charger la collecte de la disposition de l'affichage des données lors de la mise en page est verrouillée) et j'ai donc trouvé que seulement mettrereloadData()
avant le changement de disposition a fait le tour (sans que cette étrange mise en garde). En tout cas merci pour votre thread, il me permet de gagner beaucoup de temps 🙂reloadData
avantperformBatchUpdates
et lasetCollectionViewLayout
dans leperformBatchUpdates
achèvement bloc.Vous devriez appeler
[self.tradeFeedCollectionView invalidateLayout];
avantVous ne devriez avoir à appeler cette méthode:
J'ai eu un bug similaire, mais il s'est avéré que mon sous-vues de l'cellules ne sont pas de programme d'installation avec Mise en page Automatique. La cellule a été redimensionnement correctement, mais mon sous-vues n'étaient pas, tant il ressemblait à la taille de la cellule n'a jamais changé. Vérifier dans votre code rapidement par la mise en clipsToBounds = OUI sur votre cellulaire.contentView.
Ici, c'est le truc simple si vous souhaitez mettre à jour les dispositions de l'Utiliser partout où vous êtes à la mise à jour de la collectionView:
(Posté solution sur le nom de l'auteur de la question).
J'ai enfin trouvé une belle solution simple et.
L'marqué réponse est bonne, que je devais l'appeler,
-reloadData
sur monUICollectionView
- Toutefois, cela détruit l'animation lors de la commutation entre les deux cellules.Après avoir pris des suggestions de l'marqué réponse - j'ai juste retravaillé mon UIButton "méthode", qui modifie les cellules
J'ai trouvé que si je l'appelle:
Selon la WDDC vidéo - ce qui anime les changements fonctionne avec
-reloadData
méthode:Exemple:
J'ai trouvé que c'facilement et agréablement l'animation des cellules de genre et la mise en page en même temps, il est préférable de
reloadSections
(au lieu dereloadData
), suivie par la définition d'une nouvelle mise en page avec une animation: