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


98

是否可以指定UITableView行动画的持续时间,或者在动画完成时获取回调?

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

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

我还没有尝试过自己,但是也许可以通过一些索引路径处理来做到这一点:- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
Kalle 2012年

Answers:


3

现在,如果要执行此操作,则可以从iOS 11开始添加新功能:

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

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


这很棒。我没有注意到这一点。
丹尼尔·迪基森

207

刚遇到这个。方法如下:

物镜

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

迅速

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

2
同样,在这里可以完美地工作。iOS6和所有。这是SDK支持的适当机制,用于覆盖默认动画中的属性。也许您在CATransaction中还有其他的,运行时间更长的动画?他们被嵌套了。
karwag 2012年

1
在iOS6中非常适合我。感谢那!
阿隆(Aron)2013年

5
setAnimationDuration似乎不会影响插入/删除时间。iOS 6
Tom Redman

2
关于如何更改持续时间有什么建议吗?CATransaction setAnimationDuration:似乎没有什么不同。
Jeff Grimes 2013年

5
在iOS 5.1.1、6.1、7.0中对我来说也很好用;但是,如果您需要在动画后获取新的tableView.contentSize(就像我的情况一样),则必须使用[self performSelectorOnMainThread:withObject:waitUntilDone:]; 在setCompletionBlock中,以便在下一个runloop中调用您的委托。如果直接调用代理而不使用performSelectorOnMainThread,则会获得tableView.contentSize的旧值。
slamor

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];

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


动画持续时间似乎被忽略。
达斯汀

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()
    }

}

这样使用:

// 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)
        })

很棒的答案!这是我喜欢雨燕的原因之一
詹尼·卡罗

@GianniCarlo您也可以在ObjC中做到这一点
Cyber​​Mew

@Cyber​​Mew是的,但创建一个类别一直是这样的疼痛,特别是由于额外的文件的长名称
詹尼·卡洛

它仅在ios 11中可用,如何在ios 10中使用它?
kemdo

@kemdo为什么您说它仅在iOS 11中可用?这里的一切是iOS的2+,除了setCompletionBlock这是iOS 4以上版本
弗雷德里克·阿达

25

缩短Brent的正确答案,至少对于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
}];

但是,除了EaseInOut之外,我似乎无法覆盖默认动画曲线。


2
以这种方式(或@Brent的方式)进行行插入时,尽管会考虑到持续时间,但UITableViewRowAnimation似乎并没有得到尊重,即使我指定了UITableViewRowAnimationLeft,也似乎总是自上而下进行动画处理。在iOS 8.4上进行测试-有人有解决方案吗?
Danny

23

这是karwag答案的Swift版本

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

6

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

extension UICollectionView {

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

        self.reloadSections(sections)

        CATransaction.commit()
    }

}

1

由于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()
        }
    }
}

-8

您可以尝试将insertRowsAtIndexPath包装在

- (void)beginUpdates
- (void)endUpdates

交易,然后再进行刷新。


请参阅上面的karwag的答案。您需要解决算作“事后”的问题。
JLundell
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.