ChatGPT解决这个技术问题 Extra ChatGPT

如何在 UITableView beginUpdates/endUpdates 上检测到动画已经结束?

我正在使用包含在 beginUpdates/endUpdates 中的 insertRowsAtIndexPaths/deleteRowsAtIndexPaths 插入/删除表格单元格。调整 rowHeight 时,我也在使用 beginUpdates/endUpdates。默认情况下,所有这些操作都是动画的。

使用 beginUpdates/endUpdates 时如何检测动画已结束?

仅供参考:这也适用于 -scrollToRowAtIndexPath:atScrollPosition:animated:

R
Rudolf Adamkovič

那这个呢?

[CATransaction begin];

[CATransaction setCompletionBlock:^{
    // animation has finished
}];

[tableView beginUpdates];
// do some work
[tableView endUpdates];

[CATransaction commit];

这是因为 tableView 动画在内部使用 CALayer 动画。也就是说,他们将动画添加到任何打开的 CATransaction。如果不存在 open CATransaction(正常情况),则隐式开始一个,在当前运行循环结束时结束。但是,如果您自己开始一个,就像这里所做的那样,那么它将使用那个。


没有为我工作。动画仍在运行时调用完成块。
@MrVincenzo 您是否像片段中那样在 beginUpdatesendUpdates 之前设置了 completionBlock
[CATransaction commit] 应该在 [tableView endUpdates] 之后而不是之前调用。
如果单元格包含带有动画的视图,即 UIActivityIndicatorView,则永远不会调用完成块。
经过这么长时间,我从来不知道这一点。纯金 !!没有什么比看到一个漂亮的动画被 tableView.reloadData() 的必要邪恶杀死更糟糕的了。
M
Michael

斯威夫特版本

CATransaction.begin()

CATransaction.setCompletionBlock({
    do.something()
})

tableView.beginUpdates()
tableView.endUpdates()

CATransaction.commit()

R
Robert

如果您的目标是 iOS 11 及更高版本,则应改用 UITableView.performBatchUpdates(_:completion:)

tableView.performBatchUpdates({
    // delete some cells
    // insert some cells
}, completion: { finished in
    // animation complete
})

A
Antoni

一种可能的解决方案是从调用 endUpdates 的 UITableView 继承并覆盖其 setContentSizeMethod,因为 UITableView 会调整其内容大小以匹配添加或删除的行。这种方法也应该适用于 reloadData

为确保仅在调用 endUpdates 后才发送通知,还可以覆盖 endUpdates 并在那里设置一个标志。

// somewhere in header
@private BOOL endUpdatesWasCalled_;

-------------------

// in implementation file

- (void)endUpdates {
    [super endUpdates];
    endUpdatesWasCalled_ = YES;
}

- (void)setContentSize:(CGSize)contentSize {
    [super setContentSize:contentSize];

    if (endUpdatesWasCalled_) {
        [self notifyEndUpdatesFinished];
        endUpdatesWasCalled_ = NO;
    }
}

C
Community

您可以将您的操作包含在 UIView 动画块中,如下所示:

- (void)tableView:(UITableView *)tableView performOperation:(void(^)())operation completion:(void(^)(BOOL finished))completion
{
    [UIView animateWithDuration:0.0 animations:^{

        [tableView beginUpdates];
        if (operation)
            operation();
        [tableView endUpdates];

    } completion:^(BOOL finished) {

        if (completion)
            completion(finished);
    }];
}

归功于 https://stackoverflow.com/a/12905114/634940


这段代码对我不起作用。在 endUpdates 之后但在动画完成之前调用了完成块。
这行不通。应用此示例时,tableview 动画停止工作。
尝试延长持续时间(如 0.3 秒) - 它应该可以工作(它对我有用)
p
pixelfreak

还没有找到好的解决方案(缺少子类化 UITableView)。我现在决定使用 performSelector:withObject:afterDelay:。不理想,但可以完成工作。

更新:看起来我可以为此目的使用 scrollViewDidEndScrollingAnimation:(这是特定于我的实现,请参阅评论)。


scrollViewDidEndScrollingAnimation 仅在响应 setContentOffsetscrollRectToVisible 时被调用
@samvermette 好吧,就我而言,当调用 beginUpdates/endUpdates 时, UITableView 总是动画滚动。但这特定于我的实现,所以我同意这不是最好的答案,但它对我有用。
似乎可以将更新包含在 UIView 动画块中。请参阅下面的答案:stackoverflow.com/a/14305039/634940
c
chown

您可以像这样使用 tableView:willDisplayCell:forRowAtIndexPath:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"tableView willDisplay Cell");
    cell.backgroundColor = [UIColor colorWithWhite:((indexPath.row % 2) ? 0.25 : 0) alpha:0.70];
}

但是,当表格中已经存在的单元格从屏幕外移到屏幕上时,这也会被调用,因此它可能不是您要查找的内容。我只是查看了所有 UITableViewUIScrollView 委托方法,并且在插入单元格动画之后似乎没有任何事情要处理。

为什么不直接在 endUpdates 之后动画结束时调用你想调用的方法呢?

- (void)setDownloadedImage:(NSMutableDictionary *)d {
    NSIndexPath *indexPath = (NSIndexPath *)[d objectForKey:@"IndexPath"];
    [indexPathDelayed addObject:indexPath];
    if (!([table isDragging] || [table isDecelerating])) {
        [table beginUpdates];
        [table insertRowsAtIndexPaths:indexPathDelayed withRowAnimation:UITableViewRowAnimationFade];
        [table endUpdates];
        // --> Call Method Here <--
        loadingView.hidden = YES;
        [indexPathDelayed removeAllObjects];
    }
}

谢谢,陈。不要认为 willDisplayCell 会起作用。我需要它在动画之后发生,因为我需要在一切都解决之后进行视觉更新。
np @pixelfreak,如果我想到任何其他方式来做到这一点,我会告诉你的。