在 deleteItemsAtIndexPaths 上的 UICollectionView 中动画 contentOffset 更改
Posted
技术标签:
【中文标题】在 deleteItemsAtIndexPaths 上的 UICollectionView 中动画 contentOffset 更改【英文标题】:Animating contentOffset changes in a UICollectionView on deleteItemsAtIndexPaths 【发布时间】:2014-01-06 10:51:00 【问题描述】:我有一个UICollectionView
,可以在其中添加和删除单元格。我正在使用performBatchUpdates
进行这些更改,并且布局的动画效果符合预期。
当我滚动到内容的末尾并删除一个项目以使contentSize
减少时,问题就出现了:这会导致contentOffset
发生变化,但变化不是动画的。相反,contentOffset
在删除动画完成后立即跳转。我尝试在删除的同时手动更新contentOffset
,但这对我也不起作用。
我正在使用自定义布局,但我看到与标准流布局相同的行为,使用以下代码:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
return 1;
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
return self.items.count;
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
UICollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
UILabel *label = (UILabel *)[cell viewWithTag:1];
label.text = [self.items objectAtIndex:indexPath.item];
return cell;
- (IBAction)addItem:(UIBarButtonItem *)sender
self.runningCount++;
[self.items addObject:[NSString stringWithFormat:@"Item %u",self.runningCount]];
[self.collectionView performBatchUpdates:^
[self.collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:self.items.count-1 inSection:0]]];
completion:nil];
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
[self.items removeObjectAtIndex:indexPath.item];
[self.collectionView performBatchUpdates:^
[self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
completion:nil];
我觉得我一定遗漏了一些明显的东西,但这让我很难过。
【问题讨论】:
我希望你不介意我问,但我想知道你是否遇到过类似的情况,删除一个项目,如contentSize
缩小 & 视图滚动导致滚动到视图项目直到删除动画完成后才出现?重现的代码与您发布的代码几乎相同,所以我想您一定也看到了?我已经posted a question 解释过了;如果您有时间看一看,我将不胜感激。
【参考方案1】:
在集合视图的contentSize
缩小以至于其高度或宽度变得小于(或等于)集合视图边界的位置处可以看到动画故障。
可以使用setContentOffset:animated:
和类似方法强制批量更新块中的预期动画,但这依赖于知道删除后投影的内容大小。内容大小由集合视图布局管理,但由于我们还没有真正删除单元格,我们不能只询问布局(否则我们会得到旧大小)。
为了解决这个问题,我在自定义布局中实现了targetContentOffsetForProposedContentOffset:
方法,以根据需要调整内容偏移量。下面的代码仅考虑 Y 偏移量,足以满足我的需求:
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
if (self.collectionViewContentSize.height <= self.collectionView.bounds.size.height)
return CGPointMake(proposedContentOffset.x,0);
return proposedContentOffset;
我在一个直接的 UICollectionViewFlowLayout 子类中尝试了这一点,它也在那里完成了这项工作。
【讨论】:
很好的发现。我自己也遇到了这个问题,这个解决方案起到了作用(也许值得一提的是,如果contentInset
不为零,则可能需要考虑它)。 targetContentOffset...
的默认实现没有捕捉到这种情况似乎很奇怪 - 我将提交一个错误报告。【参考方案2】:
这对我很有效,引用自the question discussion
[self.dataArray removeObjectAtIndex:index];
[self.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]];
[self.collectionView performBatchUpdates:^
[self.collectionView reloadData];
completion:nil];
【讨论】:
以上是关于在 deleteItemsAtIndexPaths 上的 UICollectionView 中动画 contentOffset 更改的主要内容,如果未能解决你的问题,请参考以下文章
UICollectionView deleteItemsAtIndexPaths 不能正确地为补充视图设置动画
如何删除所有项目并将新项目添加到 UICollectionView?
NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记