2015-02-23 82 views
9

我正在用户交互中运行此动画,有时可能会在正在进行的动画完成之前再次运行动画。我想要做的是取消以前的动画并继续使用新动画。UIView animateWithDuration完成已完成=是,尽管被取消?

[UIView animateWithDuration:duration 
         delay:0 
        options:UIViewAnimationOptionBeginFromCurrentState 
       animations:^{ 
        self.bounds = bounds; 
       } 
       completion:^(BOOL finished) { 
        if (finished) { 
         // Do some cleanup after animating. 
        } 
       }]; 

从外观上看,这似乎是工作,但在我完成块,有人告诉我它在这两种情况下,这将导致清理代码运行过早结束。所以第一个动画的完成块在第二个动画开始后立即运行,完成= YES。我预计它有一个完成值NO和第二个(一旦它完成)有YES

有没有办法知道动画是否完成或者是否被其他人取消了?

旁注:我试着用CABasicAnimation做同样的动画,然后我拿完= NO在第一时间和YES第二次,所以我得到的行为似乎是专门针对animateWithDuration

下面是一个GIF图像,显示上述代码的执行时间为10,完成模块更新标签。正如你所看到的,finishedYES每次动画重新启动与animateWithDuration电话:

回答

11

所以我调查这进一步,我想这是一个iOS的8个具体的事情,由于动画是如何现在默认的添加剂,这意味着动画将继续并加起来而不是被取消。

在我的搜索中,我找到了a WWDC session called "Building Interruptible and Responsive Interactions"这是谈论这个。在会议中,他们声称动画将同时完成,但在我的测试中情况并非如此(请参阅问题中的GIF)。会话中提出的解决方法是让计数器保持动画开始与结束的次数,并在计数器达到零时执行动画后动作。这有点不方便,但有效。下面是调整这个问题代码:

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

+0

感谢这帮助我修复了我的动画故障,因为在iOS 9上始终保持真实。 – malhal 2016-04-18 00:57:04

+0

实际上,更好的方法是检查表示层的边界,然后知道它是否完成。 – malhal 2016-04-18 01:51:26

+0

这就是我最终做的(iOS 9.3,Swift)!谢谢您的帮助。 – 2016-06-09 14:57:29

0

你试图取消动画用什么方法?

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将返回false当动画取消。按预期

日志消息:

2015-02-23 14:13:58.625 TestPrj[47338:6070317] cancel 
2015-02-23 14:13:58.626 TestPrj[47338:6070317] done : 0 
+1

是的,但调用'removeAllAnimations'立即将视图置于其最终状态。我想通过第二次调用'animateWithDuration'来取消第一个动画。第二次调用显然会取消它(直接调用“完成”块),但是“完成的”值是“YES”而不是“NO”,所以我无法区分取消的动画和实际上是动画的区别完了。 – Blixt 2015-02-23 05:30:18

+0

@Blixt你想要实现的是使用块动画方法暂停/恢复动画。你见过这个http://stackoverflow.com/questions/15119839/uiview-animation-block-pause-both-the-animation-and-the-completion-code了吗? – Ryan 2015-02-23 05:49:01

+0

这是很整洁,但我实际上需要替换动画,因为'bounds'的动画根据用户的输入转到任意位置。有没有办法替代动画的'toValue'而不是暂停动画? – Blixt 2015-02-23 05:51:26