UICollectionView动画数据更改


83

在我的项目中,我使用UICollectionView显示图标网格。

用户可以通过单击分段控件来更改顺序,该分段控件调用具有不同NSSortDescriptor的核心数据的访存。

数据量始终相同,只是结束于不同的部分/行:

- (IBAction)sortSegmentedControlChanged:(id)sender {

   _fetchedResultsController = nil;
   _fetchedResultsController = [self newFetchResultsControllerForSort];

   NSError *error;
   if (![self.fetchedResultsController performFetch:&error]) {
       NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
   }

   [self.collectionView reloadData];
}

问题在于reloadData不会使更改生效,UICollectionView只会弹出新数据。

我应该跟踪更改前后一个单元格在哪个indexPath中,并使用[self.collectionView moveItemAtIndexPath:toIndexPath:]来执行更改动画,或者是否有更好的方法?

我对继承collectionViews没有太多的兴趣,所以任何帮助都将是很大的...

谢谢,比尔。


您是否尝试过将该reloadData调用包装在动画块中?
simon 2012年

Answers:


71

当放入UIView动画块时,reloadData不会进行动画处理,也不会可靠地进行动画处理。它希望位于UICollecitonView performBatchUpdates块中,因此请尝试以下类似操作:

[self.collectionView performBatchUpdates:^{
    [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:^(BOOL finished) {
    // do something on completion 
}];

5
是的,这似乎可行,但是仅当您有保存的节号时...否则,我将收到“无效的节数。更新(10)后收集视图中包含的节数必须等于更新之前包含在集合视图中的小节(16)”。我必须手动插入/删除部分...无论如何都接受!谢谢。
Nimrod12年

1
“手动”是指通过UICollectionView的insertSections / moveSection:toSection / deleteSections调用吗?或者是其他东西?(对不起,到目前为止,我对UICollectionView的使用具有固定数量的部分)
条纹

1
是的,通过这些方法...实现思想有点棘手,您必须记住更新前后的索引路径,该图是删除插入或移动的内容...
Nimrod7

12
这不适用于我的一区式收藏视图。我没有出错,但是也没有动画。替代-reloadSections:使其有效。
paulmelnikow

9
这个答案是不正确的,就我而言,将reloadData放入performBatchUpdates中会使我的应用程序崩溃,并说之前和之后的单元数不相同。使用reloadSections解决了我的问题。苹果的文档还指出,不要在动画块中调用reloadData
Wingzero'2

145

包裹-reloadData起来-performBatchUpdates:似乎并不会使单节集合视图产生动画。

[self.collectionView performBatchUpdates:^{
    [self.collectionView reloadData];
} completion:nil];

但是,此代码有效:

[self.collectionView performBatchUpdates:^{
    [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:nil];

9
从文档中注意:不要在要插入或删除项目的动画块中间调用reload data方法。插入和删除会自动导致表的数据被适当地更新。
拉斐尔·奥利维拉

我认为这应该是正确的答案。因为这对我有用。我只有1个部分,这无法正常工作。
Mahesh Agrawal

如果您还要插入,则不起作用。将覆盖排序动画。
安德烈斯·卡内拉

3
值得一提的是,您不需要self.collectionView performBatchUpdates调用reloadSections即可获得动画。实际上,performBatchUpdates在某些情况下,该呼叫可能会导致意外的闪烁/单元大小调整问题。
Paul Popiel

1
或者仅[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]]; reloadSections在集合视图或表视图中使用动画即可。
bauerMusic '18

67

这是我为重新加载所有部分的动画所做的:

[self.collectionView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.collectionView.numberOfSections)]];

迅捷3

let range = Range(uncheckedBounds: (0, collectionView.numberOfSections))
let indexSet = IndexSet(integersIn: range)
collectionView.reloadSections(indexSet)


3

performBatchUpdates:completion:在iOS 9模拟器上,将整个集合视图重新加载到一个块内会对我产生故障动画。如果您UICollectionViewCell要删除特定对象,或者具有索引路径,则可以deleteItemsAtIndexPaths:在该块中调用。通过使用deleteItemsAtIndexPaths:,它可以制作出流畅而漂亮的动画。

UICollectionViewCell* cellToDelete = /* ... */;
NSIndexPath* indexPathToDelete = /* ... */;

[self.collectionView performBatchUpdates:^{
    [self.collectionView deleteItemsAtIndexPaths:@[[self.collectionView indexPathForCell:cell]]];
    // or...
    [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
} completion:nil];

1
我只想说一个解决崩溃问题的方法,请在对集合视图调用performUpdates之前更新数据源(即节/项数)。
ViruMax '16

动画来自其他操作;有,而且从来没有在任何情况下为reloadData制作动画。insertItems以升序插入,并在更新后执行;deleteItems相反。
詹姆斯·布什

1

帮助文本显示:

调用此方法以重新加载集合视图中的所有项目。这将导致集合视图丢弃所有当前可见的项目并重新显示它们。为了提高效率,收集视图仅显示可见的那些单元格和补充视图。如果收集数据由于重新加载而缩小,则收集视图将相应地调整其滚动偏移量。您不应在插入或删除项目的动画块中间调用此方法。插入和删除会自动导致表的数据被适当地更新。

我认为关键部分是“导致集合视图丢弃任何当前可见的项目”。如何为其已丢弃的物品的运动设置动画?


确实不是。reloadData是一种无动画的双重操作;首先是删除操作,然后是插入操作。
詹姆士·布什
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.