iOS: a Complete 360 Degree-Rotation Using Block, Not CABasicAnimation

こ雲淡風輕ζ 提交于 2019-11-28 21:42:01

With UIView animations, Core Animation computes the shortest path between the initial transform and the final transform. The 360° rotation doesn't work because the final transform is the same as the initial transform.

For what it's worth, I've just tried the following code which makes four 90° rotations smoothly with no delay between rotations:

- (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];
        }
    }];
}

This is something iOS 7's keyframe animations are well suited to. For example, you can split one full rotation of view into three parts:

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) {}];

Note that when using UIViewKeyframeAnimationOptionCalculationModePaced you can leave all the start times and durations blank.

Here is a more complete version of neilco's rotateSpinningView.

It spins clockwise or counter clockwise. It has a completion: parameter and it starts and stops easy.

+ (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 put a very good solution but it is an infinite rotation.

Based on his code, I modify a bit to implement a one loop rotation.

#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];
    }
}];

}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!