CAShapeLayer fillcolor arc animation not working - ios

I am using below code to draw a Pie slice layer with CAShapeLayer.
CGFloat endAngle = (M_PI*2/5)-M_PI_2;
CAShapeLayer *outerBorderCircle = [CAShapeLayer layer];
int outerradius = self.frame.size.width/2;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(outerradius, outerradius)];
[path addLineToPoint:CGPointMake(outerradius, self.outerCircleBorder)];
[path addArcWithCenter:CGPointMake(outerradius,outerradius) radius:outerradius-self.outerCircleBorder startAngle:-M_PI_2 endAngle:endAngle clockwise:YES];
[path closePath];
outerBorderCircle.path = path.CGPath;
outerBorderCircle.fillColor = [UIColor whiteColor].CGColor;
outerBorderCircle.strokeColor = self.borderShadowColor.CGColor;
outerBorderCircle.lineWidth = self.outerCircleBorder;
outerBorderCircle.lineJoin = kCALineJoinRound;
outerBorderCircle.zPosition = MAXFLOAT;
CABasicAnimation *startanimation = [CABasicAnimation animationWithKeyPath:#"fillColor"];
startanimation.removedOnCompletion = YES;
startanimation.fromValue = (id)[[UIColor clearColor] CGColor];
startanimation.toValue = (id)[[UIColor whiteColor] CGColor];
startanimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
startanimation.duration = 10.0;
[startanimation setFillMode:kCAFillModeBoth];
[outerBorderCircle addAnimation:startanimation forKey:#"fillColor"];
[self.layer addSublayer:outerBorderCircle];
But animation part working as fade in fade out. But i need to animate arc kind of animation.
Please help me.

To animate the stroke you should animate those properties:
-strokeStart
-strokeEnd
From the documentation:
Combined with the strokeEnd property, this property defines the
subregion of the path to stroke. The value in this property indicates
the relative point along the path at which to begin stroking while the
strokeEnd property defines the end point. A value of 0.0 represents
the beginning of the path while a value of 1.0 represents the end of
the path. Values in between are interpreted linearly along the path
length.
[UPDATE]
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
drawAnimation.duration = timeInSeconds;
drawAnimation.fromValue = [NSNumber numberWithFloat:startAngle];
drawAnimation.toValue = [NSNumber numberWithFloat:endAngle];
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[circle addAnimation:drawAnimation forKey:#"drawCircleAnimation"];
Credits to Rob Mayoff

Related

Create coloured circle based on value(360) or percentage(100%)

This code creating a complete circle but I want to create a circle based on value either 360 or percentage 100%. IF percentage is 56% I want 56% circle. Like this based on percentage/value, I want circle.
CAShapeLayer *circle = [CAShapeLayer layer];
circle.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(29, 29) radius:27 startAngle:-M_PI_2 endAngle:2 * M_PI - M_PI_2 clockwise:YES].CGPath;
circle.fillColor = [UIColor clearColor].CGColor;
circle.strokeColor = [UIColor greenColor].CGColor;
circle.lineWidth = 4;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animation.duration = 10;
animation.removedOnCompletion = NO;
animation.fromValue = #(0);
animation.toValue = #(1);
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[circle addAnimation:animation forKey:#"drawCircleAnimation"];
[_colouredCircle.layer.sublayers makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
[_colouredCircle.layer addSublayer:circle];
That means that your toValue should match your percentage.
In your case, animation.toValue = #(0.56); would end the stroke at 56% of the circle (0...1 range).
See this answer for information about keeping the final animated value after completion.
TLDR: You have to also update the model layer.
circle.strokeStart = 0;
circle.strokeEnd = 0.56; // Your target value
...
// Your animation
Check out this circular progress bar and set colour as you want to set at particular position.

Animation for Layer in iOS

I masked an image with BezierPath.
I want to animate that mask image.
My code is as follow:
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(84.95, 205.11)];
[bezierPath addCurveToPoint: CGPointMake(122.89, 232.14) controlPoint1: CGPointMake(84.95, 205.11) controlPoint2: CGPointMake(110.81, 223.56)];
[bezierPath addCurveToPoint: CGPointMake(124.33, 233.04) controlPoint1: CGPointMake(123.37, 232.46) controlPoint2: CGPointMake(123.85, 232.78)];
[bezierPath closePath];
CAShapeLayer *maskImage = [CAShapeLayer layer];
maskImage.path = bezierPath.CGPath;
maskImage.fillColor = [[UIColor blackColor] CGColor];
_myImageView.layer.mask = maskImage;
CAShapeLayer *border = [CAShapeLayer layer];
border.path = bezierPath.CGPath;
border.strokeColor = [UIColor redColor].CGColor;
border.fillColor = [[UIColor clearColor] CGColor];
border.lineWidth = 5;
[_myImageView.layer addSublayer:border];
How can I animate this?
Thank you
Use following piece of code:
#property (nonatomic, retain) CAShapeLayer *animationLayer;
- (IBAction)drawPattern:(id)sender{
[self setup];
[self.animationLayer removeAllAnimations];
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = 10.0;
pathAnimation.fromValue = #(0);
pathAnimation.toValue = #(1);
[self.animationLayer addAnimation:pathAnimation forKey:#"strokeEnd"];
}
- (void)setup{
[self.animationLayer removeFromSuperlayer];
self.animationLayer = nil;
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(84.95, 205.11)];
[bezierPath addCurveToPoint: CGPointMake(122.89, 232.14) controlPoint1: CGPointMake(84.95, 205.11) controlPoint2: CGPointMake(110.81, 223.56)];
[bezierPath addCurveToPoint: CGPointMake(124.33, 233.04) controlPoint1: CGPointMake(123.37, 232.46) controlPoint2: CGPointMake(123.85, 232.78)];
CAShapeLayer *pathLayer = [CAShapeLayer layer];
// provide frame & bounds so that path can be drawn over that.
pathLayer.frame = CGRectMake(35, 100, 250, 200);
pathLayer.bounds = CGRectMake(35, 100, 250, 200);
pathLayer.path = bezierPath.CGPath;
pathLayer.strokeColor = [UIColor redColor].CGColor;
pathLayer.fillColor = [[UIColor clearColor] CGColor];
pathLayer.lineWidth = 6.f;
pathLayer.lineJoin = kCALineJoinRound;
[self.view.layer addSublayer:pathLayer];
[self setAnimationLayer:pathLayer];
}
Please let me know if this works for you & also if anything else comes up.
At the end of your code try below one
CAShapeLayer *pathLayer;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [aPath CGPath];
shapeLayer.strokeColor = [[UIColor greenColor] CGColor];
shapeLayer.fillColor = nil;
shapeLayer.lineWidth = 5.0f;
shapeLayer.lineJoin = kCALineJoinBevel;
[myImageView.layer addSublayer:shapeLayer];
pathLayer = shapeLayer;
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = 3.0;
pathAnimation.fromValue = #(0.0f);
pathAnimation.toValue = #(1.0f);
[pathLayer addAnimation:pathAnimation forKey:#"strokeEnd"];
We can animate the image with path using CABasicAnimation.
CABasicAnimation has position,path,transform,opacity,shadow......which including all layers keypaths,shape layer keypaths,CA layer keypaths,Text layer keypaths,Mask layer keypaths,UIView layer keypaths,Effect,Emit and replicator keypaths.
According to your question for drawing path we can use path and strokeEnd.But most prepare strokeEnd for accessing shape style properties.
So I think strokeEnd is the best one for animating the mask image with bezier path.
Below I give the code for path and strokeEnd also I diffrecicate both.
If I use animationWithKeyPath is path
The shape to be rendered and animatable.It is specifying the shape path.
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"path"];
animation.fromValue = #(0);
animation.toValue = #(1);
animation.duration = 6.0f;
[maskImage addAnimation:animation forKey:#"animatePath"];
The Path is a collection of individual components like lines and arcs that can be drawn and also animated.It is fundamental concept of Quartz 2D.
In below code I use strokeEnd
Generally if we want to access the shape style properties we can use
strokeEnd
The relative location at which to stop stroking the path and animatable.
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animation.fromValue = #(0);
animation.toValue = #(1);
animation.duration = 6.0f;
[maskImage addAnimation:animation forKey:#"strokeEnd"];
The value of this property must be in the range 0.0 to 1.0. The default value of this property is 1.0.
Also strokeEnd defines following thing
Combined with the strokeStart property, this property defines the subregion of the path to stroke. The value in this property indicates the relative point along the path at which to finish stroking while the strokeStart property defines the starting point.

Animating CAShapeLayer to follow the lline of UIBezierPath

I an trying to animate the stroke of a UIBezierPath, as if drawing with a pencil.
However, I am finding that the layer seems to be creating an entire shape by connecting my first and last points on the curve -- and this is not what I want. I simply want a line of stroke 2.0 to animate. Here is my code:
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(20.0f, 20.f)];
[path addLineToPoint:CGPointMake(20.f, 200.f)];
CGFloat radius = 6.f;
[path addArcWithCenter:CGPointMake(20.f + radius, 200.f) radius:radius startAngle:M_PI endAngle:M_PI/2 clockwise:NO];
[path addLineToPoint:CGPointMake(240, 200.f+radius)];
[path addLineToPoint:CGPointMake(240.f, 480.f)];
[path stroke];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.lineWidth = 2.0;
[self.scrollView.layer addSublayer:shapeLayer];
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = 4.f;
pathAnimation.fromValue = #(0.0f);
pathAnimation.toValue = #(1.0f);
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.6 :0.3 :0.8 :0.45];
[shapeLayer addAnimation:pathAnimation forKey:#"strokeEnd"];
and here is what it looks like:

Draw line then delete it

with Xcode for iOS, I have animated a drawn line.
I wish to delete it (or fade away) almost immediately.
I have tried to repeat the code with the colour set to clear (red for the tests) as my background is a grid pattern. But I only get the last colour line drawn.
Any ideas on drawing the lines in sequence one after each other?
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0.0,100.0)];
[path addLineToPoint:CGPointMake(150.0, 100.0)];
[path addLineToPoint:CGPointMake(155.0, 50.0)];
[path addLineToPoint:CGPointMake(160.0, 150.0)];
[path addLineToPoint:CGPointMake(165.0, 100.0)];
[path addLineToPoint:CGPointMake(350.0, 100.0)];
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = self.view.bounds;
pathLayer.path = path.CGPath;
pathLayer.strokeColor = [[UIColor greenColor] CGColor];
pathLayer.fillColor = nil;
pathLayer.lineWidth = 2.0f;
pathLayer.lineJoin = kCALineJoinBevel;
[self.view.layer addSublayer:pathLayer];
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = 1.0;
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
[pathLayer addAnimation:pathAnimation forKey:#"strokeEnd"];
}
Thanks
Add:
pathAnimation.autoreverses = true;
pathAnimation.removedOnCompletion = false;
pathAnimation.fillMode = kCAFillModeForwards;
You'll also probably want to use the animation delegate functions to remove the layer on completion.
Alternatively, if you want a delay (even slight) before the animation reverses, or want to fade it out in a different manner than reversing the animation, you can use a CAAnimationGroup to execute a series of animations on the same timeline.
Thanks for all the help.
I managed to find and successfully use code from the "Core Animation" Apple documentation. This is the first time I've managed that. Sorry for being slow, learning all the time. I had to replace "titleLayer" with "pathLayer". I'm sure that would have helped some of the suggestions.
Thanks again.
Here's my working code. Added after the code I posted above, before the last curly bracket.
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnim.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnim.toValue = [NSNumber numberWithFloat:0.0];
fadeAnim.duration = 1.5;
[pathLayer addAnimation:fadeAnim forKey:#"opacity"];
// Change the actual data value in the layer to the final value.
pathLayer.opacity = 0.0;

iOS - Animate only the 'appendPath' of an UIBezierPath

there are a lot of examples how to animate along a UIBezierPath. But i can't figure it out, how to animate only the appendPath of an UIBezierPath.
In my case i have the following example:
// Create path from view controller
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:
CGRectMake(0, 0, tutorialController.bounds.size.width,
tutorialController.bounds.size.height) cornerRadius:0];
// Create circle path
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(x, y, 2.0*radius, 2.0*radius) cornerRadius:radius];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
// Create spot layer
spotLayer = [CAShapeLayer layer];
spotLayer.path = path.CGPath;
spotLayer.fillRule = kCAFillRuleEvenOdd;
spotLayer.fillColor = [UIColor blackColor].CGColor;
spotLayer.opacity = 0.90;
So basically its a circle inside a rect and i now want to animate only the circle. In all attempts the rect was also moved.
Here is my example, how i can animate "along" a path
CGPoint pathStart = CGPointMake(96.000000, 226.000000);
CGPoint pathEnd = CGPointMake(120.000000, 300.000000);
[circlePath moveToPoint:pathStart];
[circlePath addLineToPoint:pathEnd];
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
anim.path = circlePath.CGPath;
anim.duration = 5.0;
anim.calculationMode = kCAAnimationPaced;
[spotLayer addAnimation:anim forKey:#"bezierPathAnim"];
But that is not what i want...
What i want to do is, to move my circle path (which is an appended path of a rectangle path) via animation
Does anybody has some ideas?
Regards
I solved my Problem :-)
Here is the solution...
// If there is an old path animate to the new path
if(oldPath != nil){
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"path"];
[anim setFromValue:(__bridge id)oldPath];
[anim setToValue:(__bridge id)[path CGPath]];
[anim setDuration:0.3];
[anim setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[spotLayer addAnimation:anim forKey:#"path"];
}
First of all i kept the oldPath (starting point) and then animate to the new setted path.

Resources