UIBezierPath - Animating Fill - objective-c

I have a UIBezierPath (a circle) built incrementally with:
[circlePath addArcWithCenter:clockCenter radius:radius startAngle:angleRadians endAngle:1.5*M_PI clockwise:YES];
...
[circlePath closePath];
[COLOR_CIRCLE setFill];
[circlePath fill];
Occasionally, I would like to animate the fill so that it takes a second to completely fill and follows the path as it was built (clockwise). What is the preferred method of accomplishing this? Right now I'm thinking Core Animation but I'm hoping there's a fill:withDelay or some such that I haven't stumbled upon. TIA.

You could try this:
Create a CAShapeLayer whose path is set to your shape. Use this CAShapeLayer as a mask for another layer into which you draw a filled arc/circle. Then animate the arc/circle arc angle from 0º to 360º. That might approximate the effect you want.
I can't find a "built-in" way to animate the fill as you want. There is a built-in way to animate the stroke, however:
Use a UIView with a CAShapeLayer backing it. CAShapeLayer has a path property. You can then apply an animation to the layer's strokeStart and/or strokeEnd properties.

Related

IOS::How we can implement this [Curved Progress Bar]

I need to implement this functionality.Please suggest me.
It's not working properly means it is taking the end angle for the filling colour but here mentioned the "fromValue" and "toValue" but its not going through the fromValue and toValue.
Please anyone can edit my code.
Thanks in advance.
CAShapeLayer *circle=[CAShapeLayer layer];
circle.path=[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.img_View.frame.origin.x, self.img_View.frame.origin.y) radius:50 startAngle:0 endAngle:90 clockwise:YES].CGPath;
circle.fillColor=[UIColor clearColor].CGColor;
circle.strokeColor=[UIColor greenColor].CGColor;
circle.lineWidth=16;
CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animation.duration=10;
animation.removedOnCompletion=NO;
// animation.fromValue=#(0);
animation.fromValue=[NSNumber numberWithInt:0];
animation.toValue=[NSNumber numberWithInt:20];
animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[circle addAnimation:animation forKey:#"drawCircleAnimation"];
[img_View.layer.sublayers makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
[img_View.layer addSublayer:circle];
you can do it with UIBezierPath it is very efficient to draw shapes.
The bezier path you use as a clip seems to be just a fraction of a circle, while in the image you show, the path is more complex : 2 fractions of a circle, linked by 2 lines, the whole path having a 'ring' shape.
This approach should work, I used it for a timer with the same kind of look. Although I didn't used directly AngleGradientLayer, I modified its - (CGImageRef)newImageGradientInRect:(CGRect)rect method to return a UIImage. But I had to rotate this image by + PI/2, as Pavlov gradient angular gradient starts horizontally.
I use a UIImage, because it's a background that DOESN'T change, so I saved an instance of this UIImage in my layer, and draw it whenever I update the clipping path
- (void)drawInContext:(CGContextRef)ctx {
UIBezierPath *currentPath = [self timerPath];
// other drawing code for glow (shadow) and white stroke)
CGContextAddPath(ctx, currentPath.CGPath);
// clip !
CGContextClip(ctx);
CGContextDrawImage(ctx, self.bounds, _circularGradientImage.CGImage);
//_circularGradientImage from modified newImageGradientInRect method.
}

Smooth curve between two points?

I have two CGPoints. I need to draw a curve from one to the other. How can I draw it? Core graphics or Bezier path? If so, I need some guidance please. Thank you for your help in advance.
Use UIBezierPath or CGPath .
UIBezierPath works like NSBezierPath on OS X.
In your view's drawRect: method,
Declare the object
UIBezierPath *aPath = [UIBezierPath bezierPath];
Then start the first point.
[aPath moveToPoint: startPoint];
Next add a curved segment with control points.
This is the hard part figuring out where control points need to be.
There are two kinds.
Cubic curve
[aPath addCurveToPoint: aDestinationPoint controlPoint1: aControlPoint controlPoint2: anotherControlPoint];
Quadratic curve
[aPath addQuadCurveToPoint:aDestinationPoint controlPoint: aLonelyControlPoint];
Finally, call the set method on a UIColor (NSColor on Mac).
Then stroke or fill the path.
[aPath stroke];
You might also want to set the stroke width.
Remember drawing is back to front procedurally and if you want a different color call set on a different color before the next drawing command of fill or stroke
The CG version of events is similar but more convoluted.
http://developer.apple.com/library/ios/documentation/2ddrawing/conceptual/drawingprintingios/BezierPaths/BezierPaths.html

CALayer renderInContext: Position of Drawing

I have a UIView with a custom shape drawn in drawRect:. The frame property is set to:
{5.f, 6.f, 50.f, 50.f}
Now, I render the view in an Image Context, but it is ignoring the frame property of the UIView, and always drawing the UIView in the top left.
[_shapeView.layer renderInContext:UIGraphicsGetCurrentContext()];
I tried to change the frame of the CALayer, but nothing changed. Modifying the bounds property made things worse. The only work around I found useful was:
CGRect frame = _shapeView.frame;
CGContextTranslateCTM(context, frame.origin.x, frame.origin.y);
[_shapeView.layer renderInContext:context];
But, this is impractical when I am dealing with many shapes, I want to just use the frame property.
Using CGContextTranslateCTM is the proper way to go. As renderInContext: documentation states : "Renders in the coordinate space of the layer." This means the frame origin of your layer/view is ignored.
Regarding CGContextDrawLayer, it is not made to be used with CALayer, but with CGLayer. These are two very different things, and explains your crash.

Getting a CALayer's rounded corner content area outline as a clipping path

I can create a CALayer using [CALayer layer] and then have rounded corners using layer.cornerRadius = x.
After I do this, I have a rounded rectangle layer. Is it possible for me to extract this rounded rectangle outline as a path without re-creating the path myself?
If you just want the path then surely it's easy enough to just make one?
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:layer.bounds
cornerRadius:layer.cornerRadius];
If you need to use this in CoreGraphics then just ask for it's CGPath
roundedRect.CGPath;

Is UIBezierPath the best way to make a movable rounded rectangle?

I'm making a UISlider from scratch. I started by making a rounded rectangle, which I did using the code below:
CGRect frame = CGRectMake(10, 10, self.frame.size.width, 10);
UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:10.0];
[[UIColor blueColor] setFill];
[path fill];
I saw some other options to make a rounded rectangle but thought this was the quickest way. Are there any limitations with making one using UIBezierPath? Namely, the slider needs to be able to move upon touch events, so I want to change the center property of a BezierPath. Is this possible?
You would need to either recreate the bezier path each time you need to change the slider position, or use CGContext's transform matrix to draw it in a different place.
I suggest you look at using a CALayer for the moving part of the slider. Draw the channel of the slider in view.layer, and add a sublayer in which you draw the "thumb" of the slider. Then you can just reposition the thumb layer when you need to move it.