Rotating the CAShapeLayer arc around the center with CABasicAnimation
I have an arc that I have drawn using the CAShapeLayer and I want it to rotate around the center of the circle. I am trying to get this animation using CABasicAnimation on transform.rotation property. But the pivot seems to be around a point that is not in the center of the circle.
-(void)drawRect:(CGRect)rect{
int radius = 100;
CAShapeLayer *circle = [CAShapeLayer layer];
circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) cornerRadius:radius].CGPath;
circle.fillColor = [UIColor orangeColor].CGColor;
circle.strokeColor = [UIColor blueColor].CGColor;
circle.lineWidth = 5;
circle.strokeStart = 0.0f;
circle.strokeEnd = 0.1f;
[self.layer addSublayer:circle];
CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
spinAnimation.byValue = [NSNumber numberWithFloat:2.0f*M_PI];
spinAnimation.duration = 4;
spinAnimation.repeatCount = INFINITY;
[circle addAnimation:spinAnimation forKey:@"indeterminateAnimation"];
}
I know its an old problem, but what's the way out. I redid a lot by setting layer boundaries or anchor point, but not rotating around the center yet.
circle.bounds = self.frame;
This is how I add the view to the view controller.
[self.view addSubview:[[ProgressIndicator alloc] initWithFrame:CGRectMake(50, 50, 200, 200)]];
source to share
Here's what I ended up doing. The mistake was to add animation to the sublevel, not the layer. No need to fiddle with anchorPoint or position here when rotation is just needed for the center of the circle.
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
int radius = 50;
CAShapeLayer *circle = [CAShapeLayer layer];
circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) cornerRadius:radius].CGPath;
circle.fillColor = [UIColor clearColor].CGColor;
circle.strokeColor = [UIColor blueColor].CGColor;
circle.lineWidth = 5;
circle.strokeStart = 0.0f;
circle.strokeEnd = 0.1f;
[self.layer addSublayer:circle];
}
return self; }
- (void)drawRect:(CGRect)rect {
CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
spinAnimation.byValue = [NSNumber numberWithFloat:2.0f*M_PI];
spinAnimation.duration = 4;
spinAnimation.repeatCount = INFINITY;
[self.layer addAnimation:spinAnimation forKey:@"indeterminateAnimation"]; }
source to share
Think it's better to do something like this)
CGFloat center = CGRectGetWidth(frame) / 2;
CGFloat lineWidth = 5;
CGFloat radius = center - lineWidth / 2;
CGRect bounds = frame;
bounds.origin = CGPointZero;
CAShapeLayer *spinLayer = [CAShapeLayer layer];
spinLayer.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(center, center) radius:radius startAngle:0 endAngle:0.2 clockwise:YES].CGPath;
spinLayer.fillColor = [UIColor clearColor].CGColor;
spinLayer.strokeColor = [UIColor blueColor].CGColor;
spinLayer.lineWidth = 5;
spinLayer.lineCap = kCALineCapRound;
spinLayer.bounds = bounds;
spinLayer.position = CGPointMake(center, center);
[self.layer insertSublayer:spinLayer above:nil];
And animation:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
animation.byValue = [NSNumber numberWithFloat:2.f * M_PI];
animation.duration = 1.5f;
animation.repeatCount = INFINITY;
[spinLayer addAnimation:animation forKey:@"lineRotation"];
[self setNeedsLayout];
Swift 3
var bounds = frame
bounds.origin = CGPoint.zero
let center: CGFloat = frame.size.width
let lineWidth: CGFloat = 5
let radius = center - lineWidth / 2
let spinLayer = CAShapeLayer()
spinLayer.path = UIBezierPath(arcCenter: CGPoint(x: center, y: center),
radius: radius,
startAngle: 0,
endAngle: 0.2,
clockwise: true).cgPath
spinLayer.strokeColor = UIColor.blue.cgColor
spinLayer.fillColor = UIColor.clear.cgColor
spinLayer.lineWidth = lineWidth
spinLayer.lineCap = kCALineCapRound
spinLayer.bounds = bounds
spinLayer.position = CGPoint(x: center, y: center)
view.layer.insertSublayer(spinLayer, above: nil)
let rotation = CABasicAnimation(keyPath: "transform.rotation")
rotation.byValue = NSNumber(value: 2*M_PI as Double)
rotation.duration = 1
rotation.repeatCount = Float.infinity
spinLayer.add(rotation, forKey: "lineRotation")
source to share