【问题标题】:UIView animation block pause both the animation and the completion codeUIView 动画块暂停动画和完成代码
【发布时间】:2013-02-13 17:13:07
【问题描述】:

我有一个动画块来执行一个简单的基于变换的动画,完成后会从其父视图中删除有问题的视图。

UIView *msgView = [[UIView alloc] initWithFrame:CGRectMake(160, 120, 160, 100)];

// Do stuff to set up the subviews of msgView.

// Add the msgView to the superview (ViewController) that is going to display it.

CATransform3D transform = CATransform3DMakeScale(2.5, 2.5, 1.0);

[UIView animateWithDuration:5.0 
                 animations:^(void){msgView.layer.transform = transform;}
                 completion:^(BOOL finished){[msgView removeFromSuperview];}];

然后我使用技术问答 1673 http://developer.apple.com/library/ios/#qa/qa1673/_index.html 中详述的代码 暂停动画。

-(void)pauseLayer:(CALayer*)layer
{
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
    layer.speed = 0.0;
    layer.timeOffset = pausedTime;
}

-(void)resumeLayer:(CALayer*)layer
{
    CFTimeInterval pausedTime = [layer timeOffset];
    layer.speed = 1.0;
    layer.timeOffset = 0.0;
    layer.beginTime = 0.0;
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
    layer.beginTime = timeSincePause;
}

但是,此代码不会阻止完成代码的执行。因此,为了防止代码执行,我将完成代码更改为:

completion:^(BOOL finished){if(finished == TRUE)[msgView removeFromSuperview];};

在检查完成 == TRUE 时,可防止在动画块暂停时执行完成代码。如果在“取消暂停”动画之前超过了持续时间,则不会执行完成代码。即在这种情况下,msgView 保留在 superview 中。

是否有暂停/取消暂停与完成代码关联的动画和计时器(如果发生了这种情况)?

【问题讨论】:

  • 有趣的问题。可以理解为 iOS 中的一个 bug。为了解决这个问题,我建议你去掉动画的完成部分,而是创建你自己的 NSTimer,你当前的完成是它的调用。这样,您可以在暂停层内停止计时器(通过将 fireDate 设置在很远的将来)。您将 fireDate 重置为 (timeSincePause + 5.0) 的内部 resumeLayer
  • 我希望直接获得与完成代码关联的 CAMediaTiming,就像我们对 layer 所做的那样。我认为这将是一个更好的解决方案。
  • 我在 iOS 6.1 下编写了一个测试应用程序,它的行为正确,即转换的计时器暂停。你在什么操作系统下测试?
  • iOS5.请注意,转换正在正常工作并正确暂停/取消暂停。我更关心的是在暂停/取消暂停期间和之后完成代码的行为。
  • 没错。它对我来说是 100% 工作的。当我暂停转换并等待 10 秒时,什么也没有发生。当我恢复它时,它完成后触发完成。正如预期的那样。

标签: ios objective-c uiview calayer


【解决方案1】:

正如我在上面的 cmets 中所说,似乎没有问题。以下是在 iOS 5.1 和 6.1 中测试的。

使用UIImageView *transViewUIButton *trigger 创建故事板。这是课程:

TSTViewController.h:

@property (weak, nonatomic) IBOutlet UIImageView *transView;
@property (weak, nonatomic) IBOutlet UIButton *trigger;
@property (nonatomic) NSUInteger bState;

- (IBAction)didPressTrigger:(id)sender;

TSTViewController.m:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.bState = 0;    // 0 is initial state
                        // 1 is transform being animated
                        // 2 is transform paused
                        // 3 is transform ended
}

- (IBAction)didPressTrigger:(id)sender {
    switch (self.bState) {
        case 0:
        {
            CATransform3D transform = CATransform3DMakeScale(2.5, 2.5, 1.0);
            self.bState++;
            [UIView animateWithDuration:5.0
                             animations:^(void){self.transView.layer.transform = transform;}
                             completion:^(BOOL finished){
                                 self.bState = 3;
                                 NSLog(@"Done");
                             }];
            break;
        }
        case 1:
        {
            self.bState++;
            [self pauseLayer:self.transView.layer];
            break;
        }
        case 2:
        {
            self.bState = 1;
            [self resumeLayer:self.transView.layer];
            break;
        }
        case 3:
        {
            [UIView animateWithDuration:0 animations:^(void){self.transView.layer.transform = CATransform3DIdentity;}
                             completion:^(BOOL finished) {
                                 self.bState = 0;
                                 NSLog(@"Reset");
                             }];
            break;
        }
        default:
            break;
    }
}

-(void)pauseLayer:(CALayer*)layer
{
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
    layer.speed = 0.0;
    layer.timeOffset = pausedTime;
}

-(void)resumeLayer:(CALayer*)layer
{
    CFTimeInterval pausedTime = [layer timeOffset];
    layer.speed = 1.0;
    layer.timeOffset = 0.0;
    layer.beginTime = 0.0;
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
    layer.beginTime = timeSincePause;
}

当您按下触发按钮时,动画开始。再按一次,动画停止。等待 10 秒钟,然后再次按下按钮。动画继续并结束,并记录“完成”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-14
    相关资源
    最近更新 更多