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


116

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

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


1
仅供参考:这也适用-scrollToRowAtIndexPath:atScrollPosition:animated:
Ben Lachman 2014年

Answers:


292

那这个呢?

[CATransaction begin];

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

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

[CATransaction commit];

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


7
没为我工作。在动画仍在运行时调用完成块。
mrvincenzo

2
@MrVincenzo您是否在代码段中设置了“ completionBlockbefore” beginUpdates和“ endUpdateslike”?
RudolfAdamkovič13年

2
[CATransaction commit]应该在之后之前调用[tableView endUpdates]
RudolfAdamkovič13年

6
如果单元格包含带有动画的视图(即UIActivityIndi​​catorView),则永远不会调用完成块。
markturnip

3
这段时间过后,我从来不知道这一点。纯金 !!没有什么比这更糟了,然后看到一个不错的动画因tableView.reloadData()的必要弊端而被杀死。
DogCoffee 2015年

31

迅捷版


CATransaction.begin()

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

tableView.beginUpdates()
tableView.endUpdates()

CATransaction.commit()

6

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

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

5

一种可能的解决方案是从您调用的UITableView继承endUpdates并覆盖它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;
    }
}

5

您可以将操作封装在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


4
该代码对我不起作用。在endUpdates之前但在动画完成之前调用完成块。
蒂姆·坎伯2013年

1
这行不通。应用此示例时,tableview动画停止工作。
Primoz990

尝试使持续时间(如0.3秒) -它应该工作(它的工作对我来说)
EMEM

1

尚未找到一个好的解决方案(缺少对UITableView的子类化)。我决定暂时使用performSelector:withObject:afterDelay:。不理想,但是可以完成工作。

更新:看来我可以scrollViewDidEndScrollingAnimation:用于此目的(这是特定于我的实现的,请参阅注释)。


1
scrollViewDidEndScrollingAnimation只叫响应setContentOffsetscrollRectToVisible
samvermette

@samvermette好吧,在我的情况下,当调用beginUpdates / endUpdates时,UITableView总是设置动画滚动。但这是我的实现所特有的,因此我同意这不是最佳答案,但对我有用。
pixelfreak 2012年

似乎可以将更新包含在UIView动画块中。看到我的回答如下:stackoverflow.com/a/14305039/634940
Zdenek 2013年

0

您可以这样使用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];
}

但是,当表中已有的单元格从屏幕外移动到屏幕上时,也会调用此方法,因此它可能并不是您所要查找的。我只是查看了所有UITableViewand UIScrollView委托方法,插入单元格动画后似乎没有什么要处理的。


为什么在动画结束后动画结束时不只是调用要调用的方法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不会起作用。我需要它在动画之后发生,因为我只需要在一切解决后进行视觉更新即可。
pixelfreak 2011年

np @pixelfreak,如果我想到其他方法可以通知您。
索恩
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.