IOS: full 360-degree rotation using a block, not CABasicAnimation

It should be something really simple, but I was not able to achieve this using blocks. There are questions and answers to this, but everything that I found is solved using CABasicAnimation , and not UIView Block-Based Animation, which I do after.

The following code does not work (Block-Based), without animation:

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

From my understanding, every time we use Block-Based, the animation will not occur when the UIViewAnimation Block "sees" that the initial value matches the final value. Fairly enough, to move it 360 degrees would mean that the object remains where it is. But this should be a way to use Block-Based Animation to make this animated, because the following CABasicAnimation will work flawlessly:

 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"]; 

In addition to this, the following block-based actions are performed, but there is a stop between the animations (first it rotates 180 degrees, and then 180 degrees to complete the rotation), and this is not what I get after:

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

I know that I could save a lot of time and just CABasicAnimation and use CABasicAnimation with it, but I would like to know why it works and the other one does not work this case (360 degree rotation). I hope you can give me a detailed explanation regarding this between 2 in this case and some Block-Based code that can perform a full rotation of 360 degrees.

Thanks in advance.

+8
ios core-graphics uiviewanimation cabasicanimation
source share
4 answers

With animation, UIView Core Animation computes the shortest path between the original transform and the final transform. 360 ยฐ rotation does not work because the final transformation is the same as the initial transformation.

For what it's worth, I just tried the following code, which smoothly rotates 90 ยฐ smoothly without 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]; } }]; } 
+28
source share

This is what iOS 7 keyframe animation works well. For example, you can divide one full rotation of the 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) {}]; 

Please note that when using UIViewKeyframeAnimationOptionCalculationModePaced you can leave all start and long periods blank.

+12
source share

Here is a more complete version of neilco rotateSpinningView.

It rotates clockwise or counterclockwise. It has a completion: parameter, and it starts and stops.

 + (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); } }]; } 
+3
source share

@neilco delivered a very good solution, but it's an endless rotation.

Based on his code, I modify a little to implement the rotation of one cycle.

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

}

+1
source share

All Articles