ios - 取消一个UIView动画?


是否有可能在进行中取消UIView动画? 或者我将不得不下降到CA级别?

即我做了这样的事情(也许设置结束动画行动):

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve: UIViewAnimationCurveLinear];
// other animation properties

// set view properties

[UIView commitAnimations];

但在动画完成之前,我得到动画结束事件,我想取消它(缩短)。 这可能吗? 用谷歌搜索发现有几个人问同样的问题没有答案 - 一两个人猜测这是不能做的。



Answers



我这样做的方法是为您的终点创建一个新的动画。 设置一个非常短的时间,并确保使用+setAnimationBeginsFromCurrentState:方法从当前状态开始。 当您将其设置为YES时,当前动画将被缩短。 看起来像这样:

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.1];
[UIView setAnimationCurve: UIViewAnimationCurveLinear];
// other animation properties

// set view properties

[UIView commitAnimations];



使用:

#import <QuartzCore/QuartzCore.h>

.......

[myView.layer removeAllAnimations];



最简单的方法就是立即停止某个特定视图上的所有动画:

将项目链接到QuartzCore.framework。 在你的代码的开始:

#import <QuartzCore/QuartzCore.h>

现在,当你想停止视图上的所有动画时,请说:

[CATransaction begin];
[theView.layer removeAllAnimations];
[CATransaction commit];

中线会自行工作,但是直到runloop结束(“重绘时刻”)才会有延迟。 为了防止延迟,请将命令封装在显式事务处理块中,如图所示。 这个工作提供了没有其他的变化已经在这个层在当前的runloop执行。




在iOS 4及更高版本上, 使用第二个动画UIViewAnimationOptionBeginFromCurrentState选项将第一个动画缩短。

作为一个例子,假设你有一个活动指标的视图。 您希望淡化活动指标,同时开展一些耗时的活动,并在活动结束时将其淡出。 在下面的代码中,活动指示器的视图称为activityView

- (void)showActivityIndicator {
    activityView.alpha = 0.0;
    activityView.hidden = NO;
    [UIView animateWithDuration:0.5
                 animations:^(void) {
                     activityView.alpha = 1.0;
                 }];

- (void)hideActivityIndicator {
    [UIView animateWithDuration:0.5
                 delay:0 options:UIViewAnimationOptionBeginFromCurrentState
                 animations:^(void) {
                     activityView.alpha = 0.0;
                 }
                 completion:^(BOOL completed) {
                     if (completed) {
                         activityView.hidden = YES;
                     }
                 }];
}



要取消动画,只需要在UIView动画之外设置当前正在动画的属性。 这将停止动画,UIView将跳转到您刚刚定义的设置。




如果您通过更改常量而不是视图属性来激活约束,则其他方法都不会在iOS 8上运行。

示例动画:

self.constraint.constant = 0;
[self.view updateConstraintsIfNeeded];
[self.view layoutIfNeeded];
[UIView animateWithDuration:1.0f
                      delay:0.0f
                    options:UIViewAnimationOptionCurveLinear
                 animations:^{
                     self.constraint.constant = 1.0f;
                     [self.view layoutIfNeeded];
                 } completion:^(BOOL finished) {

                 }];

解:

您需要从受约束更改及其子图层影响的任何视图的图层中删除动画。

[self.constraintView.layer removeAllAnimations];
for (CALayer *l in self.constraintView.layer.sublayers)
{
    [l removeAllAnimations];
}






以上都没有解决它对我来说,但这有助于: UIView动画立即设置属性,然后动画。 它在表示层匹配模型(set属性)时停止动画。

我解决了我的问题,那就是“我想从你看起来像你出现的地方开始动画”(“你”的意思)。 如果你想要的话,那么:

  1. 添加QuartzCore。
  2. CALayer * pLayer = theView.layer.presentationLayer;

将该位置设置为表示层

我使用了几个选项,包括UIViewAnimationOptionOverrideInheritedDuration

但是,由于苹果的文档是模糊的,我不知道它是否真的覆盖了其他动画使用时,或者只是重置定时器。

[UIView animateWithDuration:blah... 
                    options: UIViewAnimationOptionBeginFromCurrentState ... 
                    animations: ^ {
                                   theView.center = CGPointMake( pLayer.position.x + YOUR_ANIMATION_OFFSET, pLayer.position.y + ANOTHER_ANIMATION_OFFSET);
                   //this only works for translating, but you get the idea if you wanna flip and scale it. 
                   } completion: ^(BOOL complete) {}];

这应该是一个体面的解决方案。




[UIView setAnimationsEnabled:NO];
// your code here
[UIView setAnimationsEnabled:YES];



我也有同样的问题; 这些API没有任何东西可以取消某些特定的动画。 该

+ (void)setAnimationsEnabled:(BOOL)enabled

禁用所有的动画,因此不适合我。 有两个解决方案:

1)让你的动画对象成为子视图。 然后,当您要取消该视图的动画时,请移除视图或将其隐藏。 非常简单,但是如果需要保持在视图中,则需要重新创建没有动画的子视图。

2)重复动画只有一个,并作出一个委托选择器重新启动动画,如果需要,如下所示:

-(void) startAnimation {
NSLog(@"startAnim alpha:%f", self.alpha);
[self setAlpha:1.0];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:YES];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(pulseAnimationDidStop:finished:context:)];
[self setAlpha:0.1];
[UIView commitAnimations];
}

- (void)pulseAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
if(hasFocus) {
    [self startAnimation];
} else {
    self.alpha = 1.0;
}
}

-(void) setHasFocus:(BOOL)_hasFocus {
hasFocus = _hasFocus;
if(hasFocus) {
    [self startAnimation];
}
}

2)的问题是,在完成当前动画循环时总会有延迟停止动画。

希望这可以帮助。




对不起复活这个答案,但在iOS 10的东西有点改变,现在取消是可能的,你甚至可以取消优雅!

在iOS 10之后,您可以使用UIViewPropertyAnimator取消动画!

UIViewPropertyAnimator(duration: 2, dampingRatio: 0.4, animations: {
    view.backgroundColor = .blue
})
animator.stopAnimation(true)

如果通过,则取消动画,并在取消动画的位置停止。 完成方法不会被调用。 但是,如果您通过false,您将负责完成动画:

animator.finishAnimation(.start)

你可以完成你的动画并保持当前状态(.current)或者进入初始状态(.start)或者结束状态(.end)

顺便说一句,你甚至可以暂停,然后重新启动...

animator.pauseAnimation()
animator.startAnimation()

注意:如果你不想突然取消,你可以改变你的动画,甚至在暂停之后改变你的动画!




即使您以上述方式取消动画didStopSelector仍然运行。 所以,如果你的应用程序在由动画驱动的逻辑状态,你将有问题。 由于这个原因,我使用上面描述的方法使用UIView动画的上下文变量。 如果您通过上下文参数将当前状态的程序传递给动画,那么当动画停止时, didStopSelector函数可以决定是否应该执行某些操作,或者仅基于当前状态和作为上下文传递的状态值来返回。




CALayer * pLayer = self.layer.presentationLayer;
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView animateWithDuration:0.001 animations:^{
    self.frame = pLayer.frame;
}];



要暂停动画而不将状态恢复为原始或最终状态:

CFTimeInterval paused_time = [myView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
myView.layer.speed = 0.0;
myView.layer.timeOffset = paused_time;