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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7623771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 21:42:24  来源:igfitidea点击:

How to detect that animation has ended on UITableView beginUpdates/endUpdates?

iphoneobjective-ciosipad

提问by pixelfreak

I am inserting/deleting table cell using insertRowsAtIndexPaths/deleteRowsAtIndexPathswrapped in beginUpdates/endUpdates. I am also using beginUpdates/endUpdateswhen adjusting rowHeight. All these operations are animated by default.

我正在使用insertRowsAtIndexPaths/deleteRowsAtIndexPaths包裹在beginUpdates/endUpdates. 我也在beginUpdates/endUpdates调整 rowHeight时使用。默认情况下,所有这些操作都是动画的。

How can I detect that animation has ended when using beginUpdates/endUpdates?

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

回答by Rudolf Adamkovi?

What about this?

那这个呢?

[CATransaction begin];

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

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

[CATransaction commit];

This works because the tableView animations use CALayeranimations internally. That is, they add the animations to any open CATransaction. If no open CATransactionexists (the normal case), then one is implicitly began, which is ended at the end of the current runloop. But if you begin one yourself, like is done here, then it will use that one.

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

回答by Michael

Swift Version

迅捷版



CATransaction.begin()

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

tableView.beginUpdates()
tableView.endUpdates()

CATransaction.commit()

回答by Robert

If you're targeting iOS 11 and above, you should use UITableView.performBatchUpdates(_:completion:)instead:

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

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

回答by Zdenek

You can enclose your operation(s) in UIView animation block like so:

您可以将您的操作包含在 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);
    }];
}

Credits to https://stackoverflow.com/a/12905114/634940.

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

回答by Antoni

A possible solution could be to inherit from the UITableView on which you call endUpdatesand overwrite its setContentSizeMethod, since UITableView adjusts its content size to match the added or removed rows. This approach should also work for reloadData.

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

To ensure that a notification is sent only after endUpdatesis called, one could also overwrite endUpdatesand set a flag there.

为了确保只有在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;
    }
}

回答by pixelfreak

Haven't found a good solution yet (short of subclassing UITableView). I've decided to use performSelector:withObject:afterDelay:for now. Not ideal, but gets the job done.

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

UPDATE: It looks like I can use scrollViewDidEndScrollingAnimation:for this purpose (this is specific to my implementation, see comment).

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

回答by chown

You can use tableView:willDisplayCell:forRowAtIndexPath:like:

你可以使用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];
}

But this will also get called when a cell that is already in the table moves from off the screen to on the screen so it may not be exactly what you are looking for. I just looked through all the UITableViewand UIScrollViewdelegate methods and there doesnt appear to be anything to handle just after a cell is inserted animation.

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



Why not just call the method you want to be called when the animation ends after the endUpdates?

为什么不直接调用你想在动画结束时调用的方法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];
    }
}