CGPath Animation - core-animation

I need some sample code where I can animate a curve/arc path which should draw a full circle as animated?
Any input will be appreciated.
Thanks,
Sat

UPDATE: Realizing there is a better solution to this problem. Just create a circular path and animate the strokeEnd property of a CAShapeLayer from 0.0f to 1.0f. Take a look at this answer from Ole: Drawing a path with CAKeyFrameAnimation on iPhone
ORIGINAL ANSWER:
You can use a CAKeyframeAnimation and create a Core Graphics path. This code animates a layer in a parabolic pattern, but you can adapt it to draw a circle.
- (CAAnimation*)pathAnimation;
{
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path,NULL,50.0,120.0);
CGPathAddCurveToPoint(path,NULL,50.0,275.0,
150.0,275.0,
150.0,120.0);
CGPathAddCurveToPoint(path,NULL,150.0,275.0,
250.0,275.0,
250.0,120.0);
CGPathAddCurveToPoint(path,NULL,250.0,275.0,
350.0,275.0,
350.0,120.0);
CGPathAddCurveToPoint(path,NULL,350.0,275.0,
450.0,275.0,
450.0,120.0);
CAKeyframeAnimation *
animation = [CAKeyframeAnimation
animationWithKeyPath:#"position"];
[animation setPath:path];
[animation setDuration:3.0];
[animation setAutoreverses:YES];
CFRelease(path);
return animation;
}

Related

Animating a CGMutablePathRef with CAShapeLayer

I'm trying to animate a path and with the changing of it's points, as shown in the keyframes below. So, the top two points move down to the bottom and the middle point moves to the top, essentially flipping it's direction.
Here's the code I'm using to create the path:
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, nil, 1.0f, 8.0f);
CGPathAddLineToPoint(path, nil, 7.0f, 1.5f);
CGPathAddLineToPoint(path, nil, 13.0f, 8.0f);
shapeLayer = [[CAShapeLayer alloc] init];
shapeLayer.path = path;
shapeLayer.strokeColor = pathColor.CGColor;
shapeLayer.fillColor = [NSColor clearColor].CGColor;
shapeLayer.lineWidth = 2.0f;
[self.layer addSublayer: shapeLayer];
However, I've also got little idea of how to actually animate the points. All the information about animating paths online is simply changing the path start, not the actual point.
Is there a way - or a different approach - to do this? Thanks in advance.
You can animate the path of the shape layer from one path to another.
In your case you would create the paths for the initial state and for the end state as two different paths.
Note: if your two paths have a different number of segments or control points, the animation will look very strange.
Then you would create an animation for the "path" key path with those to and from values and add it to the layer you are animating. If you also want the property to change to the end state you should also update the path property to reflect the end state of the animation.
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"path"];
animation.duration = 1.0; // however long your duration should be
animation.fromValue = (__bridge id)fromPath;
animation.toValue = (__bridge id)toPath;
shapeLayer.path = toPath; // the property should reflect the end state of the animation
[shapeLayer addAnimation:animation forKey:#"myPathAnimation"];

How to draw curve with glow in CGContext - something like SKShapeNode with glowWidth

I am rewriting some of my graphics drawing code from SKShapeNodes to CGContext/CALayers. I am trying to draw a curve with glow in CGContext. This is what I used to have in SpriteKit:
CGPathRef path = …(some path)
SKShapeNode *node = [SKShapeNode node];
node.path = path;
node.glowWidth = 60;
After adding it to the scene with dark-grey background, the result was as follows:
Is it possible to draw line with such glow using CGContext but without using CIFilters? Normally I will be drawing over an non-blank context background, so I prefer not to use CIFilters after the line was drawn.
I have already tried the "shadow" solution, but the results are far from perfect:
UIGraphicsBeginImageContextWithOptions(frame.size, NO, 1);
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat glowWidth = 60.0;
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 0.0), glowWidth, [UIColor whiteColor].CGColor);
CGContextBeginPath(context);
CGContextAddPath(context, path);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextStrokePath(context);
Result (the shadow is hardly visible):
Please let me know if you have some ideas.
You can create a SKEffectNode which allows you to apply Core Image filters to all of its children. In other words, you can create a SKEffectNode then add a flower sprite as a child and the SKEffectNode would apply the Core Image effect to the flower sprite.
For more detailed information, please see the SKEffectNode Class Reference.

move uiimage inside a bezier curve

I have drawn a circle using bezier curve, I am using this circle as a mask to a uiimage view. Now, how can i move the image inside the circle without moving the circle using touches.
here is my code.
CAShapeLayer *maskLayer = [CAShapeLayer layer];
aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(220, 220)
radius:170
startAngle:0
endAngle:DEGREES_TO_RADIANS(360)
clockwise:YES];
maskLayer.backgroundColor = [[UIColor clearColor] CGColor];
maskLayer.path = [aPath CGPath];
maskLayer.masksToBounds=YES;
imageView1.layer.mask = maskLayer;
[self.view addSubview:imageView1];
The coordinates of the mask is the same as the coordinates of your views layer = it moves along with the view.
You can add the image inside another view and mask that view instead. Then you can move the image inside the other view and the mask will stay the same.
Alternatively (but really the same solution) you could keep the mask on that layer and add a sublayer with the image and move that instead.

masking UIView based on CGRect

Look at the image please :
I have UIView and CGRect. I have to check where CGRect overlays UIView and then set the mask on the area which is "opposed" to intersection. So it's blue part in the image. How to achieve that?
I know there's CGContextClipToMask but I have no idea how to use that - could someone help me with example code? Is CGContextClipToMask good direction?
Thanks!
You can assign mask layer to your UIView's layer.
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
view.layer.mask = maskLayer;
CGPathRef path = CGPathCreateMutable();
// Construct path and set it.
[maskLayer setPath:path];
CGPathRelease(path);
[maskLayer release];
Documentation: CALayer reference

Antialiased drawing in a CALayer

Greetings! I'm trying to draw a series of circles in a CALayer that resides in a zoomable UISCrollView. This is the layer that zooms on pinch. If i draw the circles using CAShapeLayer, then they zoom beautifully:
CAShapeLayer plotLayer = [CAShapeLayer layer];
plotLayer.bounds = self.bounds;
plotLayer.anchorPoint = CGPointZero;
plotLayer.position = CGPointZero;
CGMutablePathRef path = CGPathCreateMutable();
for (id one in many) {
CGRect ellipseRect = [one circleRect];
CGPathAddEllipseInRect(path, NULL, ellipseRect);
}
plotLayer.path = path
CFRelease(path);
[self.layer addSublayer:plotLayer];
[plotLayer setNeedsDisplay];
However, when i try to draw them with vanilla core graphics in my drawLayer:inContext: method, the circles get very jaggy (downright pro-aliased!) No amount of antialias jiggery-pokery seems to help:
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
CGContextSetAllowsAntialiasing(context, true);
CGContextSetShouldAntialias(context, true);
CGContextClip(context);
for (id one in many) {
CGRect ellipseRect = [one circleRect];
CGContextStrokeEllipseInRect(context, ellipseRect);
}
}
I'm trying to figure out what CAShapeLayer is doing to get such nice antialiasing so that (aside from my own edification) i can take full advantage of core graphics in my drawing rather than just the stroke/fill that i can get with CAShapeLayer. Am i just missing a transform somewhere?
Many thanks!
Short answer: contentsScale
Longer answer: (taken almost verbatim from pe8ter at Vector like drawing for zoomable UIScrollView):
You can get a better rendering by setting the contentScale property on the layer in question after zooming:
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView
withView:(UIView *)view
atScale:(float)scale
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithBool:YES]
forKey:kCATransactionDisableActions];
uglyBlurryTextLayer.contentsScale = scale;
[CATransaction commit];
}
There's a (typically excellent) description by Brad Larson of when the actual drawing occurs (spoiler, it usually only occurs once despite how many transforms are applied) at So a CALayer does not contain a content bitmap of a view?. Based on this, i can only assume that setting contentsScale causes the layer to render again.
I haven't tried this but if your circles get jaggy when resizing the view, it might be because of the interpolation quality.
Have you tried setting the interpolation quality to high?
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);