251

是否可以在动画进行时取消UIView动画?还是我必须降到CA级别?

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

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

// set view properties

[UIView commitAnimations];

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

4

17 回答 17

363

采用:

#import <QuartzCore/QuartzCore.h>

.......

[myView.layer removeAllAnimations];
于 2010-03-19T06:53:32.753 回答
115

我这样做的方法是为您的终点创建一个新动画。设置一个非常短的持续时间并确保您使用该+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];
于 2009-05-08T21:46:03.680 回答
63

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

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

#import <QuartzCore/QuartzCore.h>

现在,当你想停止视图中的所有动画时,可以这样说:

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

中间线可以自己工作,但是在运行循环完成之前会有延迟(“重绘时刻”)。为了防止这种延迟,请将命令包装在显式事务块中,如图所示。如果在当前运行循环中没有对该层执行其他更改,则此工作有效。

于 2012-01-03T23:03:22.647 回答
48

在 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;
                     }
                 }];
}
于 2011-08-11T08:30:54.467 回答
42

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

于 2010-06-19T17:09:34.700 回答
31

很抱歉恢复这个答案,但在 iOS 10 中,情况发生了一些变化,现在可以取消,您甚至可以优雅地取消!

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

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

如果你传递 true ,它会取消动画并在你取消它的地方停止。不会调用完成方法。但是,如果您传递 false 您负责完成动画:

animator.finishAnimation(.start)

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

顺便说一句,您甚至可以稍后暂停并重新启动...

animator.pauseAnimation()
animator.startAnimation()

注意:如果您不想突然取消,您可以在暂停后反转动画甚至更改动画!

于 2017-11-09T17:57:47.473 回答
12

如果您通过更改常量而不是视图属性来为约束设置动画,则其他方法都不能在 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];
}
于 2014-11-07T17:21:23.377 回答
8

如果您只想平稳地暂停/停止动画

self.yourView.layer.speed = 0;

来源:如何暂停图层树的动画

于 2015-06-29T11:02:59.250 回答
5

以上都没有为我解决它,但这有帮助:UIView动画立即设置属性,然后对其进行动画处理。当表示层匹配模型(设置属性)时,它会停止动画。

我解决了我的问题,即“我想从你看起来像你出现的地方开始制作动画”('你'意味着视图)。如果你想要那个,那么:

  1. 添加石英核心。
  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) {}];

现在这应该是一个不错的解决方案。

于 2011-08-16T17:21:54.660 回答
5
[UIView setAnimationsEnabled:NO];
// your code here
[UIView setAnimationsEnabled:YES];
于 2015-02-06T05:30:56.547 回答
2

Stephen Darlington 解决方案的 Swift 版本

UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(0.1)
// other animation properties

// set view properties
UIView.commitAnimations()
于 2017-12-26T15:09:46.620 回答
1

我也有同样的问题; 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) 的问题是动画在完成当前动画周期时总是会延迟停止。

希望这可以帮助。

于 2009-05-08T17:03:03.813 回答
1

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

于 2010-10-05T08:52:39.933 回答
0
CALayer * pLayer = self.layer.presentationLayer;
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView animateWithDuration:0.001 animations:^{
    self.frame = pLayer.frame;
}];
于 2013-01-28T14:54:35.710 回答
0

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

CFTimeInterval paused_time = [myView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
myView.layer.speed = 0.0;
myView.layer.timeOffset = paused_time;
于 2015-12-03T21:43:48.233 回答
0

当我使用UIStackView动画时,除了removeAllAnimations()我需要将一些值设置为初始值,因为removeAllAnimations()可以将它们设置为不可预测的状态。我有stackViewwithview1view2inside,一个视图应该是可见的,一个是隐藏的:

public func configureStackView(hideView1: Bool, hideView2: Bool) {
    let oldHideView1 = view1.isHidden
    let oldHideView2 = view2.isHidden
    view1.layer.removeAllAnimations()
    view2.layer.removeAllAnimations()
    view.layer.removeAllAnimations()
    stackView.layer.removeAllAnimations()
    // after stopping animation the values are unpredictable, so set values to old
    view1.isHidden = oldHideView1 //    <- Solution is here
    view2.isHidden = oldHideView2 //    <- Solution is here

    UIView.animate(withDuration: 0.3,
                   delay: 0.0,
                   usingSpringWithDamping: 0.9,
                   initialSpringVelocity: 1,
                   options: [],
                   animations: {
                    view1.isHidden = hideView1
                    view2.isHidden = hideView2
                    stackView.layoutIfNeeded()
    },
                   completion: nil)
}
于 2019-02-07T09:03:02.137 回答
0

没有一个回答的解决方案对我有用。我以这种方式解决了我的问题(我不知道这是否正确?),因为我在调用它时遇到了问题(当之前的动画尚未完成时)。我通过customAnim块传递我想要的动画。

extension UIView
{

    func niceCustomTranstion(
        duration: CGFloat = 0.3,
        options: UIView.AnimationOptions = .transitionCrossDissolve,
        customAnim: @escaping () -> Void
        )
    {
        UIView.transition(
            with: self,
            duration: TimeInterval(duration),
            options: options,
            animations: {
                customAnim()
        },
            completion: { (finished) in
                if !finished
                {
                    // NOTE: This fixes possible flickering ON FAST TAPPINGS
                    // NOTE: This fixes possible flickering ON FAST TAPPINGS
                    // NOTE: This fixes possible flickering ON FAST TAPPINGS
                    self.layer.removeAllAnimations()
                    customAnim()
                }
        })

    }

}
于 2019-08-20T11:52:05.047 回答