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

Dan*_*son 96 iphone animation cocoa-touch uitableview ios

有没有办法既可以指定UITableView行动画的持续时间,也可以在动画完成时获取回调?

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

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

kar*_*wag 201

刚碰到这个.这是怎么做的:

Objective-C的

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

迅速

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

  • `setAnimationDuration`似乎不会影响插入/删除持续时间.iOS 6 (5认同)
  • 在iOS 5.1.1,6.1,7.0中也适用于我; 但是,如果你需要在动画之后获得一个新的tableView.contentSize(就像我的情况那样),你必须使用[self performSelectorOnMainThread:withObject:waitUntilDone:]; 在setCompletionBlock中,以便在下一个runloop中调用您的委托.如果直接调用代理,没有performSelectorOnMainThread,则会获得tableView.contentSize的旧值. (5认同)
  • 再次,在这里完美无瑕.iOS6和所有.这是一个适当的SDK支持的机制,用于覆盖默认动画中的属性.也许你的CATransaction中有更多,更长时间运行的动画?你知道,它们会嵌套. (2认同)
  • 有关如何改变持续时间的任何建议吗?CATransaction setAnimationDuration:似乎没有什么区别. (2认同)

小智 38

扩展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];
Run Code Online (Sandbox Code Playgroud)

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


Fré*_*dda 26

这是一个有用的伎俩!我写了一个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()
    }

}
Run Code Online (Sandbox Code Playgroud)

这样使用:

// 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)
        })
Run Code Online (Sandbox Code Playgroud)


小智 25

缩短布伦特的好答案,对于至少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
}];
Run Code Online (Sandbox Code Playgroud)

但是,我似乎无法从EaseInOut以外的任何东西覆盖默认动画曲线.

  • 当以这种方式插入行时,或@ Brent的方式,尽管持续时间得到遵守,但UITableViewRowAnimation似乎并未得到尊重,并且即使在我指定的情况下也始终显示为自上而下的动画,例如UITableViewRowAnimationLeft.在iOS 8.4上进行测试 - 任何人都有解决方案吗? (2认同)

pri*_*ris 23

这是karwag答案的Swift版本

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


Ant*_*ine 6

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

extension UICollectionView {

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

        self.reloadSections(sections)

        CATransaction.commit()
    }

}
Run Code Online (Sandbox Code Playgroud)


Mic*_*bro 4

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

- (void)performBatchUpdates:(void (^)(void))updates 
                 completion:(void (^)(BOOL finished))completion;
Run Code Online (Sandbox Code Playgroud)

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