iOS:使用块而不是CABasic动画的完整360度旋转



这应该非常简单,但我还没有成功地使用块来工作。对此有问题和答案,但我发现的所有问题和答案都是通过使用CABasicAnimation而不是通过UIView基于块的动画来解决的,这就是我所追求的。

以下代码不起作用(基于块),没有动画:

CGAffineTransform spin = CGAffineTransformRotate(spiningView.transform, DEGREES_RADIANS(360));
CATransform3D identity = CATransform3DIdentity;
CATransform3D spin2 =  CATransform3DRotate(identity, DEGREES_RADIANS(360), 0.0f, 0.0f, 1.0f);

[UIView animateWithDuration:3.0f
                      delay:0.0f
                    options:UIViewAnimationOptionCurveLinear
                 animations:^
                 {
                     spiningView.transform = spin;
                     //spiningView.layer.transform = spin2;
                     //Have also tried the above, doesn't work either.
                 }
                 completion:^(BOOL finished)
                 {
                     spiningView.transform = spin;
                     //spiningView.layer.transform = spin2;
                 }];

据我了解,每次我们使用基于块时,都不会发生动画,当UIViewAnimation块"看到"开始值与最终值相同时。公平地说,将其设置为移动到 360 度意味着对象停留在原地。但它必须是一种使用基于块的动画来制作动画的方法,因为以下CABasicAnimation可以完美运行:

CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0f];
rotationAnimation.duration = 3.0f;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = 1;
[spiningView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];  

此外,以下基于块的工作,但在动画之间有一个停止(首先它旋转到 180 度,然后从那里再旋转 180 度以完成旋转),这不是我想要的:

[UIView animateWithDuration:3.0f
                      delay:0.0f
                    options:UIViewAnimationOptionCurveLinear
                 animations:^
                 {
                     spiningView.transform = CGAffineTransformRotate(spiningView.transform, DEGREES_RADIANS(180));;
                 }
                 completion:^(BOOL finished)
                 {                         
                     [UIView animateWithDuration:3.0f
                                           delay:0.0f
                                         options:UIViewAnimationOptionCurveLinear
                                      animations:^
                                      {
                                         spiningView.transform = CGAffineTransformRotate(spiningView.transform, DEGREES_RADIANS(360));
                                      }
                                      completion:^(BOOL finished)
                                      {
                                      }];
                 }];

我知道我可以节省很多时间,只是放弃使用CABasicAnimation并完成它,但我想知道为什么在这种情况下一个有效而另一个无效(进行 360 度旋转)。我希望你能在这种情况中的 2 和一些可以执行完整 360 度旋转的代码(基于块)之间给我一个详细的解释。

提前谢谢。

对于 UIView 动画,核心动画计算初始转换和最终转换之间的最短路径。360° 旋转不起作用,因为最终变换与初始变换相同。

对于它的价值,我刚刚尝试了以下代码,它可以平滑地进行四个 90° 旋转,旋转之间没有延迟:

- (void)rotateSpinningView
{
    [UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
        [spiningView setTransform:CGAffineTransformRotate(spiningView.transform, M_PI_2)];
    } completion:^(BOOL finished) {
        if (finished && !CGAffineTransformEqualToTransform(spiningView.transform, CGAffineTransformIdentity)) {
            [self rotateSpinningView];
        }
    }];
}
这是

iOS 7的关键帧动画非常适合的。例如,您可以将一个完整的view旋转拆分为三个部分:

CGFloat direction = 1.0f;  // -1.0f to rotate other way
view.transform = CGAffineTransformIdentity;
[UIView animateKeyframesWithDuration:1.0 delay:0.0
                               options:UIViewKeyframeAnimationOptionCalculationModePaced | UIViewAnimationOptionCurveEaseInOut
                            animations:^{
                              [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.0 animations:^{
                                view.transform = CGAffineTransformMakeRotation(M_PI * 2.0f / 3.0f * direction);
                              }];
                              [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.0 animations:^{
                                view.transform = CGAffineTransformMakeRotation(M_PI * 4.0f / 3.0f * direction);
                              }];
                              [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.0 animations:^{
                                view.transform = CGAffineTransformIdentity;
                              }];
                            }
                            completion:^(BOOL finished) {}];

请注意,使用 UIViewKeyframeAnimationOptionCalculationModePaced 时,您可以将所有开始时间和持续时间留空。

这是neilco的rotateSpinningView的更完整版本。

它顺时针或逆时针旋转。它有一个completion:参数,可以轻松启动和停止。

+ (void)rotateSpinningView:(UIView *)view direction:(BOOL)clockwise completion:(void (^)(BOOL finished))completion
{
    int dir = clockwise ? 1 : -1;
    UIViewAnimationOptions opt = UIViewAnimationOptionCurveLinear;
    if (CGAffineTransformEqualToTransform(view.transform, CGAffineTransformIdentity)) {
        opt = UIViewAnimationOptionCurveEaseIn;
    }
    else if (CGAffineTransformEqualToTransform(CGAffineTransformRotate(view.transform, dir * M_PI_2), CGAffineTransformIdentity)) {
        opt = UIViewAnimationOptionCurveEaseOut;
    }
    [UIView animateWithDuration:0.5f delay:0.0f options:opt animations:^{
        [view setTransform:CGAffineTransformRotate(view.transform, dir * M_PI_2)];
    } completion:^(BOOL finished) {
        if (finished && !CGAffineTransformEqualToTransform(view.transform, CGAffineTransformIdentity)) {
            [self rotateSpinningView:view direction:clockwise completion:completion];
        }
        else if (completion && finished && CGAffineTransformEqualToTransform(view.transform, CGAffineTransformIdentity)) {
            completion(finished);
        }
    }];
}

@neilco提出了一个非常好的解决方案,但它是一个无限旋转。

根据他的代码,我修改了一点以实现单循环旋转。

#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
- (void)rotateSpinningView:(UIView *)spiningView stop:(BOOL)stop {
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    double rads = DEGREES_TO_RADIANS(180);
    if (stop) {
        rads = DEGREES_TO_RADIANS(360);
    }
    [spiningView setTransform:CGAffineTransformMakeRotation(rads)];
} completion:^(BOOL finished) {
    if (finished && !stop && !CGAffineTransformEqualToTransform(spiningView.transform, CGAffineTransformIdentity)) {
        [self rotateSpinningView:spiningView stop:YES];
    }
}];

}

最新更新