UIView animateWithDuration 完成已完成 = YES 尽管已被取消?
UIView animateWithDuration completion has finished = YES despite being cancelled?
我在用户交互中 运行 播放此动画,有时动画可能会在正在进行的动画完成之前再次 运行。我想让它做的是取消以前的动画并继续新的动画。
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.bounds = bounds;
}
completion:^(BOOL finished) {
if (finished) {
// Do some cleanup after animating.
}
}];
从视觉上看,这似乎可行,但在我的完成块中,我被告知它在两种情况下都已完成,这导致清理代码过早 运行。所以第一个动画的完成块 运行s 在第二个动画开始后立即完成,完成 = YES
。我预计它的完成值为 NO
,第二个(完成后)为 YES
.
有没有办法知道动画是完成了还是被其他人取消了?
旁注:我尝试用 CABasicAnimation
制作相同的动画,然后第一次完成 = NO
,第二次完成 YES
,所以我得到的行为似乎特定于 animateWithDuration
.
这是一个 GIF,显示了上述代码的运行情况,持续时间为 10,完成块更新了标签。如您所见,每次使用 animateWithDuration
调用重新启动动画时,finished
就是 YES
:
你试过什么方法取消动画?
theView_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[theView_ setBackgroundColor:[UIColor magentaColor]];
[self.view addSubview:theView_];
[UIView animateWithDuration:10
animations:^{
theView_.frame = CGRectMake(200, 200, 50, 50);
} completion:^(BOOL finished) {
NSLog(@"done : %@", @(finished));
if(finished) {
}
else {
}
}];
[self performSelector:@selector(cancelAnimation) withObject:nil afterDelay:2];
cancelAnimation方法如下:
- (void)cancelAnimation {
NSLog(@"cancel");
[theView_.layer removeAllAnimations];
}
finished
会在动画取消时returnfalse
。
日志消息符合预期:
2015-02-23 14:13:58.625 TestPrj[47338:6070317] cancel
2015-02-23 14:13:58.626 TestPrj[47338:6070317] done : 0
所以我进一步调查了这一点,我认为这是 iOS 8 特定的事情,因为动画现在默认是相加的,这意味着动画将继续并相互累加而不是正在取消。
在我的搜索中,我发现 a WWDC session called "Building Interruptible and Responsive Interactions" 谈到了这个。在会话中,他们声称动画将同时完成,但在我的测试中并非如此(请参阅问题中的 GIF)。会话中建议的解决方法是让计数器继续计算动画开始和完成的次数,并在计数器达到零时执行 post 动画操作。这有点hacky,但有效。这是为此调整的问题代码:
// Add this property to your class.
self.runningAnimations++;
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.bounds = bounds;
}
completion:^(BOOL finished) {
if (--self.runningAnimations == 0) {
// Do some cleanup after animating.
}
}];
显然,每种类型的动画都需要一个单独的计数器,这样最后可能会有点混乱,但我认为没有更好的方法,除非您直接开始使用 CAAnimation
。
我在用户交互中 运行 播放此动画,有时动画可能会在正在进行的动画完成之前再次 运行。我想让它做的是取消以前的动画并继续新的动画。
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.bounds = bounds;
}
completion:^(BOOL finished) {
if (finished) {
// Do some cleanup after animating.
}
}];
从视觉上看,这似乎可行,但在我的完成块中,我被告知它在两种情况下都已完成,这导致清理代码过早 运行。所以第一个动画的完成块 运行s 在第二个动画开始后立即完成,完成 = YES
。我预计它的完成值为 NO
,第二个(完成后)为 YES
.
有没有办法知道动画是完成了还是被其他人取消了?
旁注:我尝试用 CABasicAnimation
制作相同的动画,然后第一次完成 = NO
,第二次完成 YES
,所以我得到的行为似乎特定于 animateWithDuration
.
这是一个 GIF,显示了上述代码的运行情况,持续时间为 10,完成块更新了标签。如您所见,每次使用 animateWithDuration
调用重新启动动画时,finished
就是 YES
:
你试过什么方法取消动画?
theView_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[theView_ setBackgroundColor:[UIColor magentaColor]];
[self.view addSubview:theView_];
[UIView animateWithDuration:10
animations:^{
theView_.frame = CGRectMake(200, 200, 50, 50);
} completion:^(BOOL finished) {
NSLog(@"done : %@", @(finished));
if(finished) {
}
else {
}
}];
[self performSelector:@selector(cancelAnimation) withObject:nil afterDelay:2];
cancelAnimation方法如下:
- (void)cancelAnimation {
NSLog(@"cancel");
[theView_.layer removeAllAnimations];
}
finished
会在动画取消时returnfalse
。
日志消息符合预期:
2015-02-23 14:13:58.625 TestPrj[47338:6070317] cancel
2015-02-23 14:13:58.626 TestPrj[47338:6070317] done : 0
所以我进一步调查了这一点,我认为这是 iOS 8 特定的事情,因为动画现在默认是相加的,这意味着动画将继续并相互累加而不是正在取消。
在我的搜索中,我发现 a WWDC session called "Building Interruptible and Responsive Interactions" 谈到了这个。在会话中,他们声称动画将同时完成,但在我的测试中并非如此(请参阅问题中的 GIF)。会话中建议的解决方法是让计数器继续计算动画开始和完成的次数,并在计数器达到零时执行 post 动画操作。这有点hacky,但有效。这是为此调整的问题代码:
// Add this property to your class.
self.runningAnimations++;
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.bounds = bounds;
}
completion:^(BOOL finished) {
if (--self.runningAnimations == 0) {
// Do some cleanup after animating.
}
}];
显然,每种类型的动画都需要一个单独的计数器,这样最后可能会有点混乱,但我认为没有更好的方法,除非您直接开始使用 CAAnimation
。