ios UITableView 行动画持续时间和完成回调

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3832474/
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 17:49:10  来源:igfitidea点击:

UITableView row animation duration and completion callback

iosiphoneuitableviewanimationcocoa-touch

提问by Daniel Dickison

Is there a way to either specify the duration for UITableView row animations, or to get a callback when the animation completes?

有没有办法指定 UITableView 行动画的持续时间,或者在动画完成时获得回调?

What I would like to do is flash the scroll indicators after the animation completes. Doing the flash before then doesn't do anything. So far the workaround I have is to delay half a second (that seems to be the default animation duration), i.e.:

我想做的是在动画完成后闪烁滚动指示器。在此之前进行闪光不会做任何事情。到目前为止,我的解决方法是延迟半秒(这似乎是默认的动画持续时间),即:

[self.tableView insertRowsAtIndexPaths:newRows
                      withRowAnimation:UITableViewRowAnimationFade];
[self.tableView performSelector:@selector(flashScrollIndicators)
                     withObject:nil
                     afterDelay:0.5];

采纳答案by Micha? Ziobro

Nowadays if you want to do this there is new function starting from iOS 11:

如今,如果您想这样做,则从 iOS 11 开始有新功能:

- (void)performBatchUpdates:(void (^)(void))updates 
                 completion:(void (^)(BOOL finished))completion;

In updates closures you place the same code as in beginUpdates()/endUpdates section. And the completion is executed after all animations.

在更新闭包中放置与 beginUpdates()/endUpdates 部分相同的代码。并且完成在所有动画之后执行。

回答by karwag

Just came across this. Here's how to do it:

刚好碰到这个。这是如何做到的:

Objective-C

目标-C

[CATransaction begin];
[tableView beginUpdates];
[CATransaction setCompletionBlock: ^{
    // Code to be executed upon completion
}];
[tableView insertRowsAtIndexPaths: indexPaths
                 withRowAnimation: UITableViewRowAnimationAutomatic];
[tableView endUpdates];
[CATransaction commit];

Swift

迅速

CATransaction.begin()
tableView.beginUpdates()
CATransaction.setCompletionBlock {
    // Code to be executed upon completion
}
tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
tableView.endUpdates()
CATransaction.commit()

回答by Brent

Expanding on karwag's fine answer, note that on iOS 7, surrounding the CATransaction with a UIView Animation offers control of the table animation duration.

扩展karwag 的好答案,请注意,在 iOS 7 上,使用 UIView Animation 围绕 CATransaction 提供对表格动画持续时间的控制。

[UIView beginAnimations:@"myAnimationId" context:nil];

[UIView setAnimationDuration:10.0]; // Set duration here

[CATransaction begin];
[CATransaction setCompletionBlock:^{
    NSLog(@"Complete!");
}];

[myTable beginUpdates];
// my table changes
[myTable endUpdates];

[CATransaction commit];
[UIView commitAnimations];

The UIView animation's duration has no effect on iOS 6. Perhaps iOS 7 table animations are implemented differently, at the UIView level.

UIView 动画的持续时间对 iOS 6 没有影响。也许 iOS 7 表格动画在 UIView 级别的实现方式不同。

回答by Frédéric Adda

That's one hell of a useful trick! I wrote a UITableView extension to avoid writing CATransaction stuff all the time.

这是一个非常有用的技巧!我写了一个 UITableView 扩展来避免一直写 CATransaction 的东西。

import UIKit

extension UITableView {

    /// Perform a series of method calls that insert, delete, or select rows and sections of the table view.
    /// This is equivalent to a beginUpdates() / endUpdates() sequence, 
    /// with a completion closure when the animation is finished.
    /// Parameter update: the update operation to perform on the tableView.
    /// Parameter completion: the completion closure to be executed when the animation is completed.

    func performUpdate(_ update: ()->Void, completion: (()->Void)?) {

        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)

        // Table View update on row / section
        beginUpdates()
        update()
        endUpdates()

        CATransaction.commit()
    }

}

This is used like so:

这是这样使用的:

// Insert in the tableView the section we just added in sections
self.tableView.performUpdate({
            self.tableView.insertSections([newSectionIndex], with: UITableViewRowAnimation.top)

        }, completion: {
            // Scroll to next section
            let nextSectionIndexPath = IndexPath(row: 0, section: newSectionIndex)
            self.tableView.scrollToRow(at: nextSectionIndexPath, at: .top, animated: true)
        })

回答by visnu

Shortening Brent's fine answer, for at least iOS 7 you can wrap this all tersely in a [UIView animateWithDuration:delay:options:animations:completion:] call:

缩短布伦特的好答案,至少对于 iOS 7,您可以将其简洁地包装在 [UIView animateWithDuration:delay:options:animations:completion:] 调用中:

[UIView animateWithDuration:10 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
  [self.tableView beginUpdates];
  [self.tableView endUpdates];
} completion:^(BOOL finished) {
  // completion code
}];

though, I can't seem to override the default animation curve from anything other than EaseInOut.

不过,我似乎无法从 EaseInOut 以外的任何东西覆盖默认动画曲线。

回答by primulaveris

Here's a Swift version of karwag's answer

这是karwag 答案的 Swift 版本

    CATransaction.begin()
    tableView.beginUpdates()
    CATransaction.setCompletionBlock { () -> Void in
        // your code here
    }
    tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
    tableView.endUpdates()
    CATransaction.commit()

回答by Antoine

For me I needed this for a collectionView. I've made a simple extension to solve this:

对我来说,我需要这个作为 collectionView。我做了一个简单的扩展来解决这个问题:

extension UICollectionView {

    func reloadSections(sections: NSIndexSet, completion: () -> Void){
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)

        self.reloadSections(sections)

        CATransaction.commit()
    }

}

回答by Stanislau Baranouski

As tableView's performBatchmethod is available starting from iOS 11only, you can use following extension:

由于 tableView 的performBatch方法仅从iOS 11开始可用,您可以使用以下扩展名:

extension UITableView {
func performUpdates(_ updates: @escaping () -> Void, completion: @escaping (Bool) -> Void) {
        if #available(iOS 11.0, *) {
            self.performBatchUpdates({
                updates()
            }, completion: completion)
        } else {
            CATransaction.begin()
            beginUpdates()
            CATransaction.setCompletionBlock {
                completion(true)
            }
            updates()
            endUpdates()
            CATransaction.commit()
        }
    }
}

回答by Jordan

You could try to wrap the insertRowsAtIndexPath in a

您可以尝试将 insertRowsAtIndexPath 包装在

- (void)beginUpdates
- (void)endUpdates

transaction, then do the flash afterwards.

交易,然后进行闪光。