我有一批动画调用,通过遍历数组调用 . 所有这些调用都嵌套在封装动画块中,以便它们并行有效地执行 . 我也有一个完成块,我只想在所有嵌套动画完成后触发 .
问题是嵌套动画的持续时间是未知的,所以我不能简单地计算出最后一个完成的调用,并在此调用中设置完成块 . 类似地,我无法计算持续时间并在完成块上使用延迟调用 .
希望一个例子可以使这更清楚 . 这是我正在尝试做的(非常简化)版本:
-(void) animateStuff:(CGFloat)animationDuration withCompletionBlock:(void) (^)(BOOL)completionBlock {
// encapsulating animation block so that all nested animations start at the same time
[UIView animateWithDuration:animationDuration animations:^{
for(MyObject* object in self.array) {
// this method contains other [UIView animateWithDuration calls...
[self animationOfUnknownDurationWithObject:object nestedCompletionBlock:^(BOOL finished) {
// what I effectively what here is:
if(last animation to finish) {
completionBlock(YES);
}
}];
}
}]; // cannot use the completion block for the encapsulating animation block, as it is called straight away
}
通过使用dispatch_groups和异步调用提供的功能,如下所述:
http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
显然是理想的,但是UIView animateWithDuration调用本身就是一个异步调用,因此在dispatch_group_async中调用它将无法正常工作 .
我知道我可以做一些事情,比如让一个__block计数变量在nestedCompletionBlock中递减,作为确定哪一个是最后一个的方法,但在我所拥有的代码中这是非常混乱的(上面是一个简化的例子) .
有这样做的好方法吗?也许某种方式同步进行animateWithDuration,以便它可以与dispatch_group_async一起使用?
在iOS 5.0上工作 .
UPDATE:
@抢-
谢谢您的回答!这几乎解决了我的问题 - 以前没有考虑过CATransaction,猜测我应该先问一下然后再问一下 . :)
但是仍有一个问题 . 正如我之前提到的,我的例子被简化了,剩下的问题来自于动画具有嵌套的完成块(即链接动画),我需要将其包含在封闭的事务中 .
例如,如果我运行以下代码:
-(void) testAnim {
NSArray* testArray = [NSArray arrayWithObjects:self.redView, self.blueView, nil];
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
NSLog(@"All animations complete!");
}];
for(UIView* view in testArray) {
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
NSLog(@"2nd stage complete");
}];
NSLog(@"Animation 2nd stage");
[UIView animateWithDuration:2 animations:^{
setX(view, 100);
}];
} [CATransaction commit];
}];
NSLog(@"animation 1st stage");
[UIView animateWithDuration:2 animations:^{
setX(view, 150);
}];
}[CATransaction commit];
}
} [CATransaction commit];
}
我得到以下输出:
2011-12-08 15:11:35.828 testProj [51550:f803]动画第1阶段
2011-12-08 15:11:35.831 testProj [51550:f803]动画第1阶段
2011-12-08 15:11:37.832 testProj [51550:f803]动画第2阶段
2011-12-08 15:11:37.834 testProj [51550:f803]动画第2阶段
2011-12-08 15:11:37.848 testProj [51550:f803]所有动画完成!
2011-12-08 15:11:39.834 testProj [51550:f803]第二阶段完成
2011-12-08 15:11:39.851 testProj [51550:f803]第二阶段完成
我需要的是只有在所有内部操作结束后才会触发"All animations complete!"事件 .
也许与我将每个块绑定到特定操作的事实有关?
无论如何,我自己的完成块参数只会引发同样的问题 .
有任何想法吗?
2 回答
将整个事物包裹在
CATransaction
中,并设置事务的completionBlock
. 这是我的测试:如果你还没有,你需要添加QuartzCore框架 .
关于您更新的问题:由于您是从完成块创建新动画,因此这些新动画将不会成为原始事务的一部分,因此原始事务不会等待它们完成 .
通过使用带有延迟值的
+[UIView animateWithDuration:delay:options:animations:completion:]
在正确的时间启动后一个动画,将每个以后的动画作为原始事务的一部分启动可能是最简单的 .它可能会帮助你 .