在 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 单元格删除

如何删除所有项目并将新项目添加到 UICollectionView?

分配的变量引用在哪里,在堆栈中还是在堆中?

NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记

秋的潇洒在啥?在啥在啥?