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

时间:2011-10-02 00:06:57

标签: iphone objective-c ios ipad

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

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

7 个答案:

答案 0 :(得分:286)

这个怎么样?

[CATransaction begin];

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

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

[CATransaction commit];

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

答案 1 :(得分:27)

Swift版

CATransaction.begin()

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

tableView.beginUpdates()
tableView.endUpdates()

CATransaction.commit()

答案 2 :(得分: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的信用。

答案 3 :(得分:4)

可能的解决方案是从您调用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;
    }
}

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

如果您定位到iOS 11及更高版本,则应改用UITableView.performBatchUpdates(_:completion:)

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

答案 6 :(得分: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];
}

但是当桌面中已有的单元格从屏幕移动到屏幕上时,也会调用它,因此它可能不是您正在寻找的内容。我只是查看了所有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];
    }
}