取消UIView动画?

时间:2009-02-16 23:19:41

标签: ios core-animation uiviewanimation

是否有可能在UIView动画播放过程中取消它?或者我是否必须降至CA级别?

即。我做过类似的事情(也可能设置一个结束动画动作):

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

// set view properties

[UIView commitAnimations];

但是在动画完成之前我得到动画结束事件,我想取消它(剪短它)。这可能吗?谷歌搜索周围发现一些人问同一个问题没有答案 - 一两个人推测它无法完成。

17 个答案:

答案 0 :(得分:357)

使用:

#import <QuartzCore/QuartzCore.h>

.......

[myView.layer removeAllAnimations];

答案 1 :(得分:113)

我这样做的方法是为你的终点创建一个新的动画。设置一个非常短的持续时间,并确保使用+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];

答案 2 :(得分:62)

在特定视图中停止所有动画的最简单方法,立即,是这样的:

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

#import <QuartzCore/QuartzCore.h>

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

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

中间线本身可以工作,但是在runloop完成之前有一段延迟(“重绘时刻”)。要防止该延迟,请将命令包装在显式事务块中,如图所示。如果在当前的runloop中没有对该层执行任何其他更改,则无法进行此操作。

答案 3 :(得分:47)

在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;
                     }
                 }];
}

答案 4 :(得分:40)

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

答案 5 :(得分:20)

很抱歉重新获得此答案,但在iOS 10中有些事情发生了变化,现在可以取消,甚至可以优雅取消!

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

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

如果您传递true,则取消动画,并在您取消动画的位置停止。不会调用完成方法。但是,如果你传递假,你有责任完成动画:

animator.finishAnimation(.start)

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

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

animator.pauseAnimation()
animator.startAnimation()

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

答案 6 :(得分:9)

如果您通过更改常量而不是视图属性来设置约束动画,则其他任何方法都不适用于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];
}

答案 7 :(得分:8)

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

self.yourView.layer.speed = 0;

来源:How to pause the animation of a layer tree

答案 8 :(得分:5)

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

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

  1. 添加QuartzCore。
  2. CALayer * pLayer = theView.layer.presentationLayer;
  3. 将位置设置为表示层

    我使用了一些选项,包括UIViewAnimationOptionOverrideInheritedDuration

    但是因为Apple的文档很模糊,我不知道它在使用时是否真的会覆盖其他动画,或者只是重置定时器。

    [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) {}];
    

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

答案 9 :(得分:5)

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

答案 10 :(得分: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)的问题是,当完成当前动画周期时,总是会延迟停止动画。

希望这有帮助。

答案 11 :(得分:1)

斯蒂芬达林顿解决方案的斯威夫特版本

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

// set view properties
UIView.commitAnimations()

答案 12 :(得分: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()
                }
        })

    }

}

答案 13 :(得分:0)

在处理UIStackView动画时,除了removeAllAnimations()之外,我还需要将一些值设置为初始值,因为removeAllAnimations()可以将它们设置为不可预测的状态。我有stackView,里面有view1view2,应该可以看到一个视图,而一个视图应该隐藏:

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)
}

答案 14 :(得分:0)

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

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

答案 15 :(得分:0)

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

答案 16 :(得分:0)

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