代码之家  ›  专栏  ›  技术社区  ›  philsquared

取消uiview动画?

  •  230
  • philsquared  · 技术社区  · 15 年前

    可以取消A吗 UIView 正在进行动画?或者我必须降到CA级别?

    也就是说,我已经做过类似的事情(也可以设置一个结束动画动作):

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

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

    16 回复  |  直到 5 年前
        1
  •  113
  •   Stephen Darlington    15 年前

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

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.1];
    [UIView setAnimationCurve: UIViewAnimationCurveLinear];
    // other animation properties
    
    // set view properties
    
    [UIView commitAnimations];
    
        2
  •  350
  •   Jim Heising    13 年前

    用途:

    #import <QuartzCore/QuartzCore.h>
    
    .......
    
    [myView.layer removeAllAnimations];
    
        3
  •  62
  •   matt    12 年前

    最简单的停止方法 全部的 特定视图上的动画, 立即 是这样的:

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

    #import <QuartzCore/QuartzCore.h>
    

    现在,当你想停止一个视图上所有动画的轨迹时,请这样说:

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

    中间一行本身就可以工作,但是会有一个延迟,直到runloop完成(“重绘时刻”)。要防止这种延迟,请将命令包装在显式事务块中,如图所示。如果当前运行循环中没有对该层执行其他更改,则可以执行此操作。

        4
  •  45
  •   i_am_jorf    11 年前

    在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;
                         }
                     }];
    }
    
        5
  •  40
  •   tomtaylor    14 年前

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

        6
  •  16
  •   Tiago Almeida Pete W    6 年前

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

    iOS 10之后,您可以使用 UIViewPropertyAnimator !

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

    如果通过“真”,它将取消动画,并在取消动画的位置停止。不会调用完成方法。但是,如果传递“假”,则负责完成动画:

    animator.finishAnimation(.start)
    

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

    顺便说一下,您甚至可以稍后暂停和重新启动…

    animator.pauseAnimation()
    animator.startAnimation()
    

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

        7
  •  9
  •   Nikola Lajic    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];
    }
    
        8
  •  8
  •   Victor    9 年前

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

    self.yourView.layer.speed = 0;
    

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

        9
  •  5
  •   pablasso Jordan    12 年前

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

    我解决了我的问题,“我想从你出现的地方动画”(“你”是指视图)。如果你想要,那么:

    1. 添加QualthCype。
    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) {}];
    

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

        10
  •  5
  •   ideawu    9 年前
    [UIView setAnimationsEnabled:NO];
    // your code here
    [UIView setAnimationsEnabled:YES];
    
        11
  •  1
  •   Carl    15 年前

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

    + (void)setAnimationsEnabled:(BOOL)enabled

    禁用所有动画,因此不适用于我。有两种解决方案:

    1)使动画对象成为子视图。然后,如果要取消该视图的动画,请删除该视图或将其隐藏。非常简单,但如果需要保持子视图在视图中,则需要重新创建不带动画的子视图。

    2)只重复一个anim,并在需要时使代理选择器重新启动anim,如下所示:

    -(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)的问题是,当动画完成当前动画循环时,始终存在延迟停止动画。

    希望这有帮助。

        12
  •  1
  •   lucamegh    6 年前

    斯蒂芬·达林顿解决方案的快速版本

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(0.1)
    // other animation properties
    
    // set view properties
    UIView.commitAnimations()
    
        13
  •  0
  •   pablasso Jordan    12 年前

    即使按上述动画方式取消动画 didStopSelector 仍然运行。因此,如果您的应用程序中有由动画驱动的逻辑状态,那么您将遇到问题。出于这个原因,按照上面描述的方法,我使用上下文变量 UIView 动画。如果通过上下文参数将程序的当前状态传递给动画,则当动画停止时, 数字选择器 函数可以根据当前状态和作为上下文传递的状态值来决定它应该做什么,还是只返回。

        14
  •  0
  •   Thunder Rabbit Jonathan Delean    11 年前
    CALayer * pLayer = self.layer.presentationLayer;
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView animateWithDuration:0.001 animations:^{
        self.frame = pLayer.frame;
    }];
    
        15
  •  0
  •   tommybananas    8 年前

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

    CFTimeInterval paused_time = [myView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
    myView.layer.speed = 0.0;
    myView.layer.timeOffset = paused_time;
    
        16
  •  0
  •   Paul T.    5 年前

    当我和 UIStackView 动画,另外 removeAllAnimations() 我需要设置一些初始值,因为 移除动画()) 可以将它们设置为不可预测的状态。我有 stackView 具有 view1 view2 在内部,一个视图应该可见,一个隐藏:

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