Slippery circular behavior during animation using CA

I wanted to create a circular slider that you can drag and animate. So far I have managed to create a slider and use the drag handle to move it and even animate it. Sometimes the animation goes wrong (wrong direction or shortest direction). I subclassed UIView (soon there will be UIControl, I just wanted to get the animation on the right) added a PanGestureRecognizer and several layers for the drawing.

enter image description here

So how do I fix this strange behavior? I could help me here, I would be grateful :)

Here's a sample project -> http://cl.ly/2l0O3b1I3U0X

Thanks a lot!

EDIT:

Here's the drawing code:

CALayer *aLayer = [CALayer layer]; aLayer.bounds = CGRectMake(0, 0, 170, 170); aLayer.position = self.center; aLayer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1); self.handleHostLayer = [CALayer layer]; self.handleHostLayer.bounds = CGRectMake(0, 0, 170, 170); self.handleHostLayer.position = CGPointMake(CGRectGetMaxX(aLayer.bounds) - 170/2.0, CGRectGetMaxY(aLayer.bounds) - 170/2.0); [aLayer addSublayer:self.handleHostLayer]; [self.layer addSublayer:aLayer]; self.handle = [CALayer layer]; self.handle.bounds = CGRectMake(0, 0, 50, 50); self.handle.cornerRadius = 25; self.handle.backgroundColor = [UIColor whiteColor].CGColor; self.handle.masksToBounds = NO; self.handle.shadowOffset = CGSizeMake(3.0, 0.0); self.handle.shadowRadius = 0; self.handle.shadowOpacity = .15; self.handle.shadowColor = [UIColor blackColor].CGColor; [self.handleHostLayer addSublayer:self.self.handle]; 

Here's the animation code:

 CGFloat handleTarget = ToRad(DEG); CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; rotationAnimation.fromValue = @([[self.handleHostLayer valueForKeyPath:@"transform.rotation"] floatValue]); rotationAnimation.toValue = @(handleTarget); rotationAnimation.duration = .5; rotationAnimation.removedOnCompletion = NO; rotationAnimation.fillMode = kCAFillModeForwards; rotationAnimation.cumulative = YES; rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; [self.handleHostLayer addAnimation:rotationAnimation forKey:@"transform.rotation"]; 
+4
source share
1 answer

Ok, I looked at your project. Your problem is that at an angle and from angles, not both fall into the range 0โ‰คษธ <2ฯ€.

You can see what they do by adding and removing 2ฯ€, until both of them are in this range.

 CGFloat fromAngle = [[self.handleHostLayer valueForKeyPath:@"transform.rotation"] floatValue]; CGFloat toAngle = handleTarget; while (fromAngle >= 2.0*M_PI) { fromAngle -= 2*M_PI; } while (toAngle >= 2.0*M_PI) { toAngle -= 2*M_PI; } while (fromAngle < 0.0) { fromAngle += 2*M_PI; } while (toAngle < 0.0) { toAngle += 2*M_PI; } CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; rotationAnimation.fromValue = @(fromAngle); rotationAnimation.toValue = @(toAngle); // As before... 

Other things you can change is the misuse of removeOnCompletion . I made a long explanation in this answer about why this is bad.

In short: you are not animating the value that you think you are animating, as you inadvertently enter the difference between the value of the layer property and what you see on the screen.

Skip this line together. You can also skip the missing cumulative line, since you are not repeating the animation. Now, if your animations are not pasted: set the model value to the final value before adding the animation to it.

+1
source

Source: https://habr.com/ru/post/1491809/


All Articles