UICollectionView水平滚动,删除最后一项,动画不起作用

Amy*_*all 12 cocoa-touch uikit ios uicollectionview

我有一个UICollectionView.它水平滚动,只有一行项目,行为类似于分页UIScrollView.我正在制作Safari选项卡选项卡的内容,因此您仍然可以看到每个项目的边缘.我只有一个部分.

如果我删除的项目不是最后一项,则一切都按预期工作,新项目从右侧滑入.

如果我删除了最后一项,那么集合视图的滚动位置会跳转到第N-1项(不能平滑地设置动画),然后我会看到第N项(我删除的项)淡出.

此行为与我所做的自定义布局无关,因为即使我将其切换为使用普通流布局也会发生这种情况.我正在使用以下内容删除项目:

[self.tabCollectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]];
Run Code Online (Sandbox Code Playgroud)

还有其他人经历过这个吗?它是UICollectionView中的错误,是否有解决方法?

rbr*_*own 4

我设法使用标准来实现我的实现UICollectionViewFlowLayout。我必须手动创建动画。

首先,我使用基本动画使删除的单元格淡出:

- (void)tappedCloseButtonOnCell:(ScreenCell *)cell {

    // We don't want to close our last screen.
    if ([self screenCount] == 1u) {
        return;
    }

    [UIView animateWithDuration:UINavigationControllerHideShowBarDuration
                     animations:^{
                         // Fade out the cell.
                         cell.alpha = 0.0f;
                     }
                     completion:^(BOOL finished) {

                         NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
                         UIViewController *screen = [self viewControllerAtIndex:indexPath.item];

                         [self removeScreen:screen animated:YES];
                     }];
}
Run Code Online (Sandbox Code Playgroud)

接下来,我使集合视图滚动到上一个单元格。滚动到所需的单元格后,我将删除已删除的单元格。

- (void)removeScreen:(UIViewController *)screen animated:(BOOL)animated {

    NSParameterAssert(screen);

    NSInteger index = [[self.viewControllerDictionaries valueForKeyPath:kViewControllerKey] indexOfObject:screen];

    if (index == NSNotFound) {
        return;
    }

    [screen willMoveToParentViewController:nil];

    if (animated) {

        dispatch_time_t popTime = DISPATCH_TIME_NOW;
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index
                                                 inSection:0];

        // Disables user interaction to make sure the user can't interact with
        // the collection view during the time between when the scroll animation
        // ends and the deleted cell is removed.
        [self.collectionView setUserInteractionEnabled:NO];

        // Scrolls to the previous item, if one exists. If we are at the first
        // item, we just let the next screen slide in from the right.
        if (index > 0) {
            popTime = dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC);
            NSIndexPath *targetIndexPath = [NSIndexPath indexPathForItem:index - 1
                                                  inSection:0];
            [self.collectionView scrollToItemAtIndexPath:targetIndexPath
                                        atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
                                                animated:YES];
        }

        // Uses dispatch_after since -scrollToItemAtIndexPath:atScrollPosition:animated:
        // doesn't have a completion block.
        dispatch_after(popTime, dispatch_get_main_queue(), ^{

            [self.collectionView performBatchUpdates:^{
                [self.viewControllerDictionaries removeObjectAtIndex:index];
                [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
                [screen removeFromParentViewController];
                [self.collectionView setUserInteractionEnabled:YES];
            } completion:NULL];
        });

    } else {
        [self.viewControllerDictionaries removeObjectAtIndex:index];
        [self.collectionView reloadData];
        [screen removeFromParentViewController];
    }

    self.addPageButton.enabled = YES;
    [self postScreenChangeNotification];
}
Run Code Online (Sandbox Code Playgroud)

唯一有点问题的部分是dispatch_after(). 不幸的是,-scrollToItemAtIndexPath:atScrollPosition:animated:没有完成块,所以我不得不模拟它。为了避免计时问题,我禁用了用户交互。这可以防止用户在删除单元格之前与集合视图进行交互。

我必须注意的另一件事是,由于单元重复使用,我必须将单元的 alpha 重置回 1。

我希望这对您使用 Safari 风格的选项卡选择器有所帮助。我知道您的实现与我的不同,我希望我的解决方案也适合您。