如何重置/重新启动动画并使其连续出现?

11

所以,我对iOS编程还比较新手,接手了前同事的一个项目。我们正在构建一个包含仪表盘UI的应用程序。当有数据到达时,我们希望能够平稳地将“图层”(指针图像)从当前角度顺时针旋转到新的目标角度。以下是我们拥有的东西,适用于数据传输慢的情况:

-(void) MoveNeedleToAngle:(float) target
{
   static float old_Value = 0.0;
   CABasicAnimation *rotateCurrentPressureTick = [CABasicAnimation animationWithKeyPath:@"transform.rotation");
   [rotateCurrentPressureTick setDelegate:self];
   rotateCurrentPressureTick.fromValue = [NSSNumber numberWithFloat:old_value/57.2958];
   rotateCurrentPressureTick.removedOnCompletion=NO;
   rotateCurrentPressureTick.fillMode=kCAFillModeForwards;
   rotateCurrentPressureTick.toValue=[NSSNumber numberWithFloat:target/57.2958];
   rotateCurrentPressureTick.duration=3; // constant 3 second sweep

   [imageView_Needle.layer addAnimation:rotateCurrentPressureTick forKey:@"rotateTick"];
   old_Value = target;
}
问题在于我们有一个新的数据方案,其中新数据可以更快地进入(并调用上述方法),在动画完成之前。我认为正在发生的是,动画从旧目标重新启动到新目标,这使得它非常跳跃。
因此,我想知道如何修改上述函数以添加连续/可重启行为,具体步骤如下:
1. 检查当前动画是否正在进行中, 2. 如果是,则找出当前动画角度在哪里,然后 3. 取消当前动画,并从当前旋转到新目标旋转开始一个新动画。
是否可能将该行为构建到上述函数中?
谢谢。如果问题似乎不够了解,请原谅,我已经学习并理解了上述对象/方法,但不是专家。
2个回答

4

如果您添加以下这段神奇的代码,您可以使用现有方法来实现此操作:

    - (void)removeAnimationsFromView:(UIView*)view {
        CALayer *layer = view.layer.presentationLayer;
        CGAffineTransform transform = layer.affineTransform;
        [layer removeAllAnimations];
        view.transform = transform;
    }

表现层封装了动画的实际状态。视图本身不携带动画状态属性,当您设置动画结束状态时,视图会在触发动画后立即获取该状态。在动画期间,您“看到”的是表现层。

此方法会捕获取消动画时表现层的状态,并将该状态应用于视图。

现在您可以在动画方法中使用此方法,代码如下:

-(void) MoveNeedleToAngle:(float) target{
    [self removeAnimationsFromView:imageView_Needle];
    id rotation = [imageView_Needle valueForKeyPath:@"layer.transform.rotation.z"];
    CGFloat old_value = [rotation floatValue]*57.2958;

   // static float old_value = 0.0;
    CABasicAnimation *rotateCurrentPressureTick = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    [rotateCurrentPressureTick setDelegate:self];
    rotateCurrentPressureTick.fromValue = [NSNumber numberWithFloat:old_value/57.2958];
    rotateCurrentPressureTick.removedOnCompletion=NO;
    rotateCurrentPressureTick.fillMode=kCAFillModeForwards;
    rotateCurrentPressureTick.toValue=[NSNumber numberWithFloat:target/57.2958];
    rotateCurrentPressureTick.duration=3; // constant 3 second sweep

    [imageView_Needle.layer addAnimation:rotateCurrentPressureTick forKey:@"rotateTick"];

    old_value = target;

}

我对你的方法进行了最小化的更改:我还会做一些编码风格上的变化,但它们与你的问题无关。
顺便说一下,我建议你以弧度为单位输入你的方法,而不是角度,这将意味着你可以删除那些57.2958常数。

这很好,但我会做一个改变。不要在UIView上设置变换,而是调用layer.setAffineTransform。从清晰度的角度来看,这更符合你正在做的事情(最终结果可能相同,但我自己喜欢事情更加清晰明了)。 - Mark A. Donohoe

1

您可以从呈现层获取当前旋转角度,然后将其设置为toValue角度。无需保留旧值。

-(void) MoveNeedleToAngle:(float) targetRadians{ 

    CABasicAnimation *animation =[CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    animation.duration=5.0;
    animation.fillMode=kCAFillModeForwards;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    animation.removedOnCompletion=NO;

    animation.fromValue = [NSNumber numberWithFloat: [[layer.presentationLayer valueForKeyPath: @"transform.rotation"] floatValue]];
    animation.toValue = [NSNumber numberWithFloat:targetRadians];
   // layer.transform= CATransform3DMakeRotation(rads, 0, 0, 1);
   [layer addAnimation:animation forKey:@"rotate"];
}

我发现另一种方法(上面有注释的行)是不使用fromValue和toValue,而是直接设置图层变换。这将产生相同的动画,但presentationLayer和model将保持同步。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接