Objective c 第二个animateWithDuration调用禁用动画

Objective c 第二个animateWithDuration调用禁用动画,objective-c,core-graphics,objective-c-blocks,uiviewanimation,Objective C,Core Graphics,Objective C Blocks,Uiviewanimation,我认为这是一个非常简单的动画案例。有一个视图位于0 alpha,除非它在具有一种类型的事件的未来动画之前变为1,或者在具有另一种类型的事件的几秒钟内变为1。我的问题是,当连续调用这两个事件时,实际上会运行以下代码: [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){ self->bkgView.alpha

我认为这是一个非常简单的动画案例。有一个视图位于0 alpha,除非它在具有一种类型的事件的未来动画之前变为1,或者在具有另一种类型的事件的几秒钟内变为1。我的问题是,当连续调用这两个事件时,实际上会运行以下代码:

    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
    self->bkgView.alpha = 1.0;
} completion:^(BOOL finished){}];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
    self->bkgView.alpha = 1.0;
} completion:^(BOOL finished){
    NSLog(@"completion finished: %d", finished);
    if (finished)
        [UIView animateWithDuration:0.5 delay:3 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
            self->bkgView.alpha = 0;
        } completion:^(BOOL finished){}];
}];
我认为第二次呼叫只是取消了第一次呼叫,并从第一次呼叫所在的位置接管,因此我将闪烁到alpha 1几秒钟。实际发生的是根本没有动画,完成块被立即调用,finished为true,因此没有取消的迹象。我想我应该问问自己,我做错了什么,而不是在这个看似微不足道的案子上撞脑袋

编辑:我是说代码很琐碎,但下面是整个viewcontroller,如果您想尝试,您可以将其放在新的单视图项目上:

#import "ViewController.h"

@interface ViewController () {
    UIView *bkgView;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    CGFloat x = 20;;
    for (NSString *str in @[@"show", @"flash", @"both"]) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        [button addTarget:self action:NSSelectorFromString(str) forControlEvents:UIControlEventTouchUpInside];
        [button setTitle:str forState:UIControlStateNormal];
        button.backgroundColor = [UIColor grayColor];
        button.frame = CGRectMake(x, 100, 80, 40);
        [self.view addSubview:button];
        x += 100;
    }
    bkgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 100)];
    bkgView.backgroundColor = [UIColor blackColor];
    bkgView.alpha = 0;
    [self.view addSubview:bkgView];
}

-(void)both {
    [self show];
    [self flash];
}

-(void)show {
    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
        self->bkgView.alpha = 1.0;
    } completion:^(BOOL finished){}];
}

-(void)flash {
    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
        self->bkgView.alpha = 1.0;
    } completion:^(BOOL finished){
            [UIView animateWithDuration:0.5 delay:3 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
                self->bkgView.alpha = 0;
            } completion:^(BOOL finished){}];
    }];
}

它加载三个按钮。如果单击“显示”,它将在矩形中淡出。如果你点击“闪光”,它会在一个矩形中消失3秒钟,然后消失。我的问题是,如果您单击“两者”,这在这个简单的示例中可能没有多大意义,但会模拟连续调用show和flash动作,这在我的原始代码中可能会发生。我希望它的行为与“flash”相同(因为它应该立即接管“show”功能),但它什么也不做,矩形没有显示。

好的-一些事情正在进行

试试这段代码——根据您的示例稍微修改一下。我已将“淡入”持续时间更改为
1.5秒,将“淡出”持续时间更改为
2.5秒(可在
viewDidLoad
末尾更改),以便我们可以看到更多的情况。我还添加了一些
NSLog()

#import "SequentialAnimViewController.h"

@interface SequentialAnimViewController () {
    UIView *bkgView;
    double dur1;
    double dur2;
    NSDate *start;
}
@end

@implementation SequentialAnimViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    CGFloat x = 20;;
    for (NSString *str in @[@"show", @"flash", @"both"]) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        [button addTarget:self action:NSSelectorFromString(str) forControlEvents:UIControlEventTouchUpInside];
        [button setTitle:str forState:UIControlStateNormal];
        button.backgroundColor = [UIColor grayColor];
        button.frame = CGRectMake(x, 100, 80, 40);
        [self.view addSubview:button];
        x += 100;
    }
    bkgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 100)];
    bkgView.backgroundColor = [UIColor blackColor];
    bkgView.alpha = 0;
    [self.view addSubview:bkgView];
    
    dur1 = 1.5; //0.3;
    dur2 = 2.5; //0.5;
    
    start = [NSDate date];
}

-(void)both {
    [self show];
    [self flash];
}

-(void)show {
    [UIView animateWithDuration:dur1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
        NSLog(@"anim A started.... \t %f", [[NSDate date] timeIntervalSinceDate:self->start]);
        self->bkgView.alpha = 1.0;
    } completion:^(BOOL finished){
        NSLog(@"anim A finished: %d \t %f", finished, [[NSDate date] timeIntervalSinceDate:self->start]);
    }];
}

-(void)flash {
    [UIView animateWithDuration:dur1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
        NSLog(@"anim B started.... \t %f", [[NSDate date] timeIntervalSinceDate:self->start]);
        self->bkgView.alpha = 1.0;
    } completion:^(BOOL finished){
        NSLog(@"anim B finished: %d \t %f", finished, [[NSDate date] timeIntervalSinceDate:self->start]);
        [UIView animateWithDuration:self->dur2 delay:3 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
            NSLog(@"anim C started.... \t %f", [[NSDate date] timeIntervalSinceDate:self->start]);
            self->bkgView.alpha = 0;
        } completion:^(BOOL finished){
            NSLog(@"anim C finished: %d \t %f", finished, [[NSDate date] timeIntervalSinceDate:self->start]);
        }];
    }];
}

@end
首先要尝试的是点击“Flash”。通过调试控制台输出,您应该可以看到预期的结果:

anim B started....   2.780529
anim B finished: 1   4.282427
anim C started....   4.282540
anim C finished: 1   9.784028
“动画B已启动”无关紧要,因为它是
viewDidLoad
和点击“Flash”之间经过的时间

“动画B已完成:1”显示
completion==true
,从“B已开始”起经过的时间约为1.5秒

“动画C启动”将在B完成后几乎瞬间发生

现在,“anim C finished:1”(completion==true)的运行时间可能会让您感到惊讶,因为2.5秒的动画需要5.5秒。这是因为您在
延迟发生之前进入了动画块。所以

3-second delay + 2.5-second anim == 5.5
这是我们的第一条线索,为什么你的“两个”都没有做你认为应该做的事情

下一步要尝试的是-重新启动应用程序以保持清晰-然后点击“显示”。。。调试输出将是:

anim A started....   2.039016
anim A finished: 1   3.541033
同样,“started”是从
viewDidLoad
到点击“Show”和“finished:1”(completion==true)之间经过的时间,经过的时间为1.5秒

但现在,当黑色视图仍在显示时,再次点击“显示”:

等等。。。1.5秒动画只花了0.000562秒

这是因为black view的alpha已经是了==1。。。因此,从1.0设置动画到1.0不需要任何时间

这里需要注意的一个关键点是:动画不考虑正在设置动画的属性的条件。它评估属性本身

那么,当我们点击“两者”时会发生什么?重新启动应用程序并点击按钮

以下是我的调试输出:

anim A started....   1.744193
anim B started....   1.744692
anim B finished: 1   1.745148
anim C started....   1.745233
anim A finished: 0   1.745463
anim C finished: 1   7.246692
同样,“started”是从
viewDidLoad
到点击“两者”之间经过的时间

然后,我们经过了以下时间:

0.0004989
0.000456
0.000085
0.000229
5.501229
发生的事情如下:

  • 点击后,开始从alpha==0到alpha==1设置动画
  • 立即开始从alpha==1到alpha==1制作动画。。。不需要时间,也不会发生实际动画
  • 完成那个动画
  • 立即开始从alpha==1到alpha==0设置动画(延迟3秒)
  • 第一部动画未完成
  • 最终动画运行,但我们看不到动画,因为0:1动画从未完成
您需要记住的是,属性会立即设置。。。它不会等待视觉动画完成

希望这不是太多的信息来模糊对正在发生的事情的理解


编辑

至于
UIViewAnimationOptionBeginFromCurrentState
,请尝试以下操作

将持续时间更改为5秒:

dur1 = 5.0; //0.3;
然后点击“显示”。。。这将是一个非常缓慢的“淡入”。。。2秒钟后,再次点击“显示”。它将继续动画

show
方法更改为:

-(void)show {
    double f = bkgView.alpha == 0.0 ? 1.0 : 0.0;
    
    [UIView animateWithDuration:dur1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
        NSLog(@"anim A started.... \t %f", [[NSDate date] timeIntervalSinceDate:self->start]);
        self->bkgView.alpha = f;
    } completion:^(BOOL finished){
        NSLog(@"anim A finished: %d \t %f", finished, [[NSDate date] timeIntervalSinceDate:self->start]);
    }];
}

你可以点击显示,看着它慢慢褪色,在渐变中间再次显示TAP,并看着它慢慢地从它所在的点淡出。


差异(主要)是由于您的“两者”方法,即您立即调用下一个动画。

很难用您的描述和您发布的代码来说明。“试着整理一份报告。”唐玛格·姆雷补充道。好吧——不完全清楚你想做什么。在本例中,点击显示时,您希望黑色视图“淡入”。。。等3秒钟。。。然后消失?如果我快速点击两次会发生什么?在任何alpha处停止“淡入”,然后等待3并淡出?如果我点击,让它淡入,然后在3秒钟内点击立即淡出?您可以定义两个CABASICANIATION,并将带有动画键的应用于CALayer*bkgLayer或bkgView.layer,该层由发送方调用,或在init或viewDidLoad中调用。此时,您定义了一个淡入淡出的块,并定义了一个空块,该空块将被一个块覆盖,该块将覆盖第一个块,并调用一个将淡入淡出的第四个块,然后调用第五个空块。在CABasicAnimation的帮助下,你的代码看起来会容易得多。@DonMag,我把例子讲得更清楚了。我想这就解释了我的错误
-(void)show {
    double f = bkgView.alpha == 0.0 ? 1.0 : 0.0;
    
    [UIView animateWithDuration:dur1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
        NSLog(@"anim A started.... \t %f", [[NSDate date] timeIntervalSinceDate:self->start]);
        self->bkgView.alpha = f;
    } completion:^(BOOL finished){
        NSLog(@"anim A finished: %d \t %f", finished, [[NSDate date] timeIntervalSinceDate:self->start]);
    }];
}