1

我的 UI 上有一个按钮,一旦按下按钮,我想每 800 毫秒闪烁一次(打开然后再次关闭)。我用以下代码做到这一点:

- (void)flickEmergencyButton {
  // Check whether an emergency is in progress...
  if (model.emergencyInProgress) {
    // ...and if so, flick the state
    self.emergencyButton.selected = !self.emergencyButton.selected;

    // Make this method be called again in 800ms
    [self performSelector:@selector(flickEmergencyButton) withObject:nil afterDelay:0.8];
  } else {
    // ...otherwise, turn the button off
    self.emergencyButton.selected = NO;
  }
}

...效果非常好,除了:UI 上还有一个 UIScrollView,当用户将手指放在上面并滚动时,按钮会冻结。虽然我完全理解为什么会这样,但我不知道该怎么办。

消息调度消息在performSelector:withObject:afterDelay当前线程上发送,即主线程,即。UI 踩踏,因此在所有其他 UI 活动结束之前不会处理消息。正确的?但我需要在 UI 线程上执行此操作,因为我无法选择/取消选择任何其他线程上的按钮,对吗?那么这里的解决方案是什么?

4

2 回答 2

4

我会推荐使用核心动画。尝试这样的事情:

-(void) flash{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3f];
    [UIView setAnimationCurve:UIViewAnimationCurveLinear];

    if( emergency ){       
        // Start flashing
        [UIView setAnimationRepeatCount:1000];
        [UIView setAnimationRepeatAutoreverses:YES];

        [btn setAlpha:0.0f];        
    }else{
        // Stop flashing
        [UIView setAnimationBeginsFromCurrentState:YES];
        [UIView setAnimationRepeatCount:1];

        [btn setAlpha:1.0f];        
    }
    emergency = !emergency;
    [UIView commitAnimations];
}

其中 btn 被声明为

@property(nonatomic, retain) IBOutlet UIButton *btn;

紧急情况是一个简单的 BOOL 变量。

调用 flash 开始和停止动画。

在此示例中,为简单起见,我们为 alpha 属性设置动画,但您可以对按钮背景颜色执行相同操作,正如 Sam 在他的回答中所说,或者您喜欢的任何属性。

希望能帮助到你。

更新:

关于在两个图像之间进行转换,请尝试调用imageFlash而不是flash

-(void) imageFlash{

    CABasicAnimation *imageAnimation = [CABasicAnimation animationWithKeyPath:@"contents"];
    [btn setImage:normalState forState:UIControlStateNormal];

    if( emergency ){        
        imageAnimation.duration = 0.5f;
        imageAnimation.repeatCount = 1000;
    }else{
        imageAnimation.repeatCount = 1;
    }

    imageAnimation.fromValue = (id)normalState.CGImage;
    imageAnimation.toValue = (id)emergencyState.CGImage;    
    [btn.imageView.layer addAnimation:imageAnimation forKey:@"animateContents"];    
    [btn setImage:normalState forState:UIControlStateNormal]; // Depending on what image you want after the animation.

    emergency = !emergency;
}

您要使用的图像在哪里normalState以及在哪里:emergencyState

声明为:

UIImage *normalState;
UIImage *emergencyState;

分配图像:

normalState = [UIImage imageNamed:@"normal.png"];
emergencyState = [UIImage imageNamed:@"alert.png"];

祝你好运!

于 2011-08-01T18:09:38.640 回答
3

虽然这感觉像是一项工作(可能是为自定义设置CoreAnimation动画),但您可以通过在适当的运行循环模式下运行来完成此操作。 backgroundColorUIControlNSTimer

前任

NSTimer *timer = [NSTimer timerWithTimeInterval:0.8f target:self selector:@selector(flicker:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

当你想停止动画时:

[timer invalidate], timer = nil;
button.selected = NO;

通过将计时器添加到 all NSRunLoopCommonModes,您不仅可以将其添加到默认的运行循环模式,而且还可以将其添加到持续处理用户交互时所处的模式 ( UITrackingRunLoopMode.)

Apple 的文档对运行循环模式和运行循环进行了更全面的解释。

于 2011-08-01T03:19:31.363 回答