【问题标题】:Alpha changing instantly with UIView animateWithDuration: instead of animatingAlpha 使用 UIView animateWithDuration 立即改变:而不是动画
【发布时间】:2025-12-30 07:00:06
【问题描述】:

我正在尝试淡入我通过为 alpha 设置动画创建的 UIView。我需要将其淡入,让它可见几秒钟,然后淡出。

淡出功能工作正常。视线平稳地消失了。但是淡入只是让视图立即出现,而不是在 0.5 秒的时间间隔内缓慢出现。

所以动画的淡入淡出似乎不起作用,只是立即将 alpha 设置为1.0。我在这里有点不知所措。任何想法我做错了什么?谢谢!

-(void)presentPopupPhrase:(NSString *)phrase 
                   inView:(UIView *)view 
             withDelegate:(id)delegate 
            andCompletion:(void (^)(BOOL completed))completion {

    MessagePopupView *pv = [[[MessagePopupView alloc] initWithFrame:self.frame andText:phrase] autorelease];
    pv.alpha = 0.0;
    [view addSubview:pv];

    [self fadeInMPV:pv 
       withDuration:self.fadeDuration 
           andDelay:self.fadeInDelay];

    [self fadeOutMPV:pv 
        withDuration:self.fadeDuration 
          afterDelay:self.fadeOutDelay 
      withCompletion:completion 
         andDelegate:delegate];
}

-(void)fadeInMPV:(MessagePopupView *)mpv 
    withDuration:(NSTimeInterval)duration 
        andDelay:(NSTimeInterval)delay 
{    
    [UIView animateWithDuration:duration 
                          delay:delay 
                        options:UIViewAnimationOptionCurveLinear 
                     animations:^{
                         mpv.alpha = 1.0;
                     } 
                     completion:nil];
}

-(void)fadeOutMPV:(MessagePopupView *)mpv
     withDuration:(NSTimeInterval)duration
       afterDelay:(NSTimeInterval)delay
     withCompletion:(void (^)(BOOL completed))completion
      andDelegate:(id)delegate 
{
    [UIView animateWithDuration:duration 
                          delay:delay 
                        options:UIViewAnimationOptionCurveLinear 
                     animations:^{
                         mpv.alpha = 0.0;
                     } 
                     completion:completion];
}

编辑:

如果有帮助,这是我从中调用它的 VC 代码:

-(void)viewDidAppear:(BOOL)animated {

    CGRect phraseFrame = CGRectMake(20, 341, 280, 65);
    PopupPhraseController *phraseController = [[[PopupPhraseController alloc] initWithFrame:phraseFrame] autorelease];

    [phraseController presentPopupPhrase:@"Test Phrase" inView:self.view withDelegate:self andCompletion:^(BOOL completed){
        if (completed) {
            NSLog(@"completed");
        } else {
            NSLog(@"not completed");
        }
        NSLog(@"blocked!");
    }];

    [super viewDidAppear:animated];
}

【问题讨论】:

    标签: objective-c animation uiview


    【解决方案1】:

    你不能像这样链接动画,因为第二个动画块实际上会导致第一个被取消。

    Linking Multiple Animations Together 有两种选择:

    1. 使用第一个动画的完成处理程序
    2. 嵌套动画但延迟第二个动画

    1. 看起来像这样

      [UIView animateWithDuration:self.fadeDuration
                            delay:self.fadeInDelay
                          options:UIViewAnimationOptionCurveLinear 
                       animations:^{
                         pv.alpha = 1.0;
                       } completion:^(BOOL finished) {
      
                         [UIView animateWithDuration:self.fadeDuration
                                               delay:self.fadeOutDelay
                                             options:UIViewAnimationOptionCurveLinear 
                                          animations:^{
                                            pv.alpha = 0.0;
      
                                          } completion:completion];
                       }];
      
    2. 看起来像这样

      [UIView animateWithDuration:self.fadeDuration
                            delay:self.fadeInDelay
                          options:UIViewAnimationOptionCurveLinear 
                       animations:^{
                         pv.alpha = 1.0;
      
                         [UIView animateWithDuration:self.fadeDuration
                                               delay:self.fadeOutDelay + self.fadeDuration
                                             options:UIViewAnimationOptionCurveLinear 
                                          animations:^{
                                            pv.alpha = 0.0;
                                          } completion:completion];
      
                       } completion:nil];
      

    问题在于您设置动画的方式。

    当您在视图上设置动画属性时,视图的支持模型会立即更新。因此,当您在第一个块中设置 alpha = 1.0 时,视图的支持数据模型的 alpha 为 1.0,然后在另一个线程上启动实际动画以显示两个值之间的插值。

    当你在第一个块之后直接定义第二个块时,视图基本上说“好的,我需要从 1.0(我在模型中的当前值)到 0.0 进行动画处理”,这就是为什么你看不到什么你期望的。

    【讨论】:

    • 太棒了。完全有道理。谢谢你的回复,保罗。
    【解决方案2】:

    感谢 Paul.s 在此处提供提示。我认为这种预期的行为有点奇怪,即使从低层次的角度来看它似乎是合乎逻辑的。

    为了扩展 Paul 的 2 个解决方案,IMO 有第 3 个解决方案。

    使用 GCD 为淡出代码添加延迟,如下所示:

    //Make sure this delay exceeds your fade-in time...
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [self fadeOutMPV:pv
            withDuration:self.fadeDuration
              afterDelay:self.fadeOutDelay
          withCompletion:completion
             andDelegate:delegate];
    });
    

    这个解决方案更好,因为执行视图控制器不仅可以完全控制何时触发淡出,还可以控制什么触发淡出(例如,用户操作)。

    【讨论】: