Drawing circle without fill IOS - ios

I am using this code to draw a circle inside a UIImageView.
CAShapeLayer *circleLayer = [CAShapeLayer layer];
// Give the layer the same bounds as your image view
[circleLayer setBounds:CGRectMake(0.0f, 0.0f, [photoView bounds].size.width,
[photoView bounds].size.height)];
// Position the circle anywhere you like, but this will center it
// In the parent layer, which will be your image view's root layer
[circleLayer setPosition:CGPointMake(coordsFinal.x + 130, coordsFinal.y + 200)];
// Create a circle path.
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:
CGRectMake(0.0f, 0.0f, 50.0f, 50.0f)];
// Set the path on the layer
[circleLayer setPath:[path CGPath]];
// Set the stroke color
[circleLayer setStrokeColor:[color CGColor]];
// Set the stroke line width
[circleLayer setLineWidth:2.0f];
// Add the sublayer to the image view's layer tree
[[photoView layer] addSublayer:circleLayer];
I would like the circle to be empty, and to have only the border. How can I remove the fill?

Set the fill color to transparent (alpha 0)
[circleLayer setFillColor:[[UIColor colorWithWhite:0 alpha:0] CGColor]];
AKA...
[circleLayer setFillColor:[[UIColor clearColor] CGColor]];
(thanks Zev)

The CAShapeLayer manual page explicitly says set fillColor to nil to perform no fill operation. That is not the same as filling with a transparent color, which some have suggested doing, as the latter will overwrite existing contents making them clear/transparent, and should be considered a destructive operation.

Related

mask doesn't work if it is assigned to a layer which is a sublayer

got a _imageView which is properly added and located
if a layer is assigned to _imageView.layer.mask, it worked:
CAShapeLayer *maskLayer = [CAShapeLayer layer];
[maskLayer setPath:maskPath;
[maskLayer setPosition:CGPointMake(50, 50)]
[_imageViewLayer setMask:maskLayer];
now the mask blocks content outside its path
however,if a layer is assigned to one of _imageView.layer.sublayers, it blocks everything:
_imageViewLayer = [CAShapeLayer layer];
CGPathRef circlePath = CGPathCreateWithEllipseInRect(CGRectMake(0, 0, 100, 100), nil);
[_imageViewLayer setPath: circlePath];
[_imageViewLayer setPosition: CGPoinMake(50, 50)];
CGPathRelease(circlePath);
[_imageViewLayer setFillColor:[[UIColor redColor] CGColor]];
[[_imageView layer] addSublayer:_imageViewLayer];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
CGPathRef maskPath = CGPathCreateWithEllipseInRect(CGRectMake(0, 0, 10, 10), nil);
[maskLayer setPath:maskPath];
CGPathRelease(maskPath);
[maskLayer setPosition: CGPoinMake(50, 50)];
[_imageViewLayer setMask: maskLayer];
if i remove the maskLayer, i can see a red circle on _imageView
could anyone give me a hint, or it's just a bug?
From Apple:
/* A layer whose alpha channel is used as a mask to select between the
* layer's background and the result of compositing the layer's
* contents with its filtered background. Defaults to nil. When used as
* a mask the layer's `compositingFilter' and `backgroundFilters'
* properties are ignored. When setting the mask to a new layer, the
* new layer must have a nil superlayer, otherwise the behavior is
* undefined. Nested masks (mask layers with their own masks) are
* unsupported. */
#property(nullable, strong) CALayer *mask;
"When setting the mask to a new layer, the new layer must have a nil superlayer, otherwise the behavior is undefined. "
Your _imageViewLayer has already had a superlayer [_imageView layer] when you are setting maskLayer to _imageViewLayer as a mask.

iOS: CAShapeLayer, Change color of outer layer

I am currently using CAShapeLayer for one of my requirement. I was successful in implementing the fillcolor, strokecolor, etc... but I wanted to change the color of outer part of that CAShapeLayer. I tried doing it with backgroundcolor, & followed many answers from SO, but was unable to do it. Could anyone guide me with the solution. Screenshot attached
Edit 1: Code for creating the layer
// create layer mask for map
CAShapeLayer *maskLayer = [CAShapeLayer layer];
mapView.layer.mask = maskLayer;
// maskLayer.backgroundColor = [[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.7] CGColor];
self.maskLayer = maskLayer;
// create shape layer for circle we'll draw on top of map (the boundary of the circle)
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.lineWidth = 3.0;
circleLayer.fillColor = [[UIColor clearColor] CGColor];
circleLayer.strokeColor = [[UIColor blackColor] CGColor];
// circleLayer.borderColor = [[UIColor blackColor] CGColor];
// circleLayer.backgroundColor = [[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.7] CGColor];
[mapView.layer addSublayer:circleLayer];
self.circleLayer = circleLayer;
Edit 2: Xcode's Viewer's Debugger
In the above image I can see that I have set the background color to self.view. But I want it to be over my map view & the the color should be semi transparent so that map data outside circle should also be visible.
Have you tried using XCode views's debugger to know where this white background belongs in your view hierarchy ?
You're using your view's maskLayer as a circle. So my guess is that this white background must be OUTSIDE your view - everything out your mask gets clipped - so you should probably try to change your viewController's view backgroundColor (or any other view that is just above your custom rounded view)
[self.view.layer setBackgroundColor:[UIColor grayColor].CGColor];
UIBezierPath *circle = [UIBezierPath bezierPathWithArcCenter:self.view.center
radius:45.0
startAngle:0
endAngle:2.0*M_PI
clockwise:YES];
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.bounds = CGRectMake(0, 0, 2.0*(45.0), 2.0*(45.0));
circleLayer.path = circle.CGPath;
circleLayer.strokeColor = [UIColor orangeColor].CGColor;
circleLayer.fillColor = [UIColor whiteColor].CGColor;
circleLayer.lineWidth = 3.0; // your line width
[self.view.layer addSublayer:circleLayer];
See if it helps you.

Draw a gesture control resizable circle in iOS

I want to draw a circle in iOS. It can be an image view or view, I want to adjust its size on gestures. Like, dragging from outside to the center, the radius of the circle should reduce and so vice versa.
Please note that I want to fix the position of that view, circle or image. I just want to adjust the size as it is dragged.
try this
- (IBAction)pinch:(UIPinchGestureRecognizer *)sender {
double scale=[sender scale];
self.view1.frame=CGRectMake(self.view1.frame.origin.x*scale, self.view1.frame.origin.y*scale, self.view1.frame.size.width*scale, self.view1.frame.size.height*scale);
[self.view1.layer setCornerRadius:5];
}
Try this.
- (IBAction)pan:(UIPanGestureRecognizer *)sender {
for (CALayer *layer in self.imageView.layer.sublayers) {
[layer removeFromSuperlayer];
}
CGPoint scale =[sender locationInView:sender.view];
CAShapeLayer *circleLayer = [CAShapeLayer layer];
[circleLayer setBounds:CGRectMake(0.0f, 0.0f, [_imageView bounds].size.width,
[_imageView bounds].size.height)];
[circleLayer setPosition:CGPointMake(CGRectGetMidX([_imageView bounds]),CGRectGetMidY([_imageView bounds]))];
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, CGRectGetWidth(_imageView.frame)+scale.x, CGRectGetHeight(_imageView.frame)+scale.y)];
[circleLayer setPath:[path CGPath]];
[circleLayer setStrokeColor:[[UIColor redColor] CGColor]];
[circleLayer setLineWidth:1.0f];
[circleLayer setFillColor:[[UIColor clearColor] CGColor]];
[[_imageView layer] addSublayer:circleLayer];
}

Arc shape not rendered smoothly

I've created an arc at a 12 o'clock position on a CAShapeLayer and added it as a sublayer onto a UIView. The arc is rough or bumpy. I tried antialiasing, corner radius, line join, and have also tried rasterizing at one point but no luck. Any ideas why it's not smooth and what to do to make it smoother? If make the same arc at 9 or 3 o'clock they are smooth, but not 12 or 6 o'clock. Appreciate any help.
Here's the code:
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddArc(path, nil, 38.25, 38.25, 25, degreesToRadians(304), degreesToRadians(236), YES);
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
[shapeLayer setAllowsEdgeAntialiasing:YES];
[shapeLayer setEdgeAntialiasingMask:kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge];
[shapeLayer setCornerRadius:2.0];
[shapeLayer setLineJoin:kCALineJoinRound];
[shapeLayer setFillColor:[[UIColor clearColor] CGColor]];
[shapeLayer setStrokeColor:[color CGColor]];
[shapeLayer setLineCap:kCALineCapRound];
[shapeLayer setLineWidth:3.0];
[shapeLayer setPath:path];
Here's a link to the arcs. Top and bottom are not smooth like on the left. They look less smooth on a device. Screen capture sort of smoothed them out more than they actually are.
http://oi57.tinypic.com/2wf4i9c.jpg
It looks like your layer is off the pixel bounds. That is, it’s rasterizing the layer, then shifting it by a fractional number of pixels before drawing. My first suggestion would be to round those x.25 values to whole numbers.
By the way, why are you passing 304, 236 as the startAngle and endAngle in CGPathAddArc()? Those parameters are in radians, not degrees.
edgeAntialiasingMask and allowsEdgeAntialiasing has to do with how the edges of the layer’s rectangular bounds are rendered, and should not affect the contents.
Edit: the difference is subtle, but when I stop using fractional values, the slight bumps in the line go away. By the way, if you post your images in .png format, it’s easier to see what’s going on, because they don’t get the artifacting from jpg compression.
// Fractional values
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddArc(path, nil, 138.25, 138.25, 25, degreesToRadians(304), degreesToRadians(236), YES);
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
[shapeLayer setLineJoin:kCALineJoinRound];
[shapeLayer setFillColor:[[UIColor clearColor] CGColor]];
[shapeLayer setStrokeColor:[UIColor blueColor].CGColor];
[shapeLayer setLineCap:kCALineCapRound];
[shapeLayer setLineWidth:3.0];
[shapeLayer setPath:path];
CGPathRelease(path);
[self.view.layer addSublayer:shapeLayer];
// Integral values
CGMutablePathRef newPath = CGPathCreateMutable();
CGPathAddArc(newPath, nil, 200, 138, 25, degreesToRadians(304), degreesToRadians(236), YES);
CAShapeLayer *newShapeLayer = [CAShapeLayer layer];
[newShapeLayer setLineJoin:kCALineJoinRound];
[newShapeLayer setFillColor:[[UIColor clearColor] CGColor]];
[newShapeLayer setStrokeColor:[UIColor blueColor].CGColor];
[newShapeLayer setLineCap:kCALineCapRound];
[newShapeLayer setLineWidth:3.0];
[newShapeLayer setPath:newPath];
CGPathRelease(newPath);
[self.view.layer addSublayer:newShapeLayer];
And the result:
When I overlay them in Difference Mode in Photoshop, you can see where the pixels differ:

Drawing a shape in a UIImageView IOS

I am trying to draw some circles inside a UIImageView with a specific image. This is what I was trying to do:
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(contextRef, 2.0);
CGContextSetStrokeColorWithColor(contextRef, [color CGColor]);
CGRect circlePoint = (CGRectMake(coordsFinal.x, coordsFinal.y, 50.0, 50.0));
CGContextStrokeEllipseInRect(contextRef, circlePoint);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[photoView addSubview:image];
The circle is drawn fine, but I would like the PhotoView to act as a mask to it. So if for example I move the UIImageView out of the UIView using an animation, I would like the circle to move with it. Important is the fact that the coordinates are relative to the whole screen.
Use Core Animation's shape layer instead.
CAShapeLayer *circleLayer = [CAShapeLayer layer];
// Give the layer the same bounds as your image view
[circleLayer setBounds:CGRectMake(0.0f, 0.0f, [photoView bounds].size.width,
[photoView bounds].size.height)];
// Position the circle anywhere you like, but this will center it
// In the parent layer, which will be your image view's root layer
[circleLayer setPosition:CGPointMake([photoView bounds].size.width/2.0f,
[photoView bounds].size.height/2.0f)];
// Create a circle path.
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:
CGRectMake(0.0f, 0.0f, 50.0f, 50.0f)];
// Set the path on the layer
[circleLayer setPath:[path CGPath]];
// Set the stroke color
[circleLayer setStrokeColor:[[UIColor redColor] CGColor]];
// Set the stroke line width
[circleLayer setLineWidth:2.0f];
// Add the sublayer to the image view's layer tree
[[photoView layer] addSublayer:circleLayer];
Now, if you animate the UIImageView that contains this layer, the layer will move with it since it is a child layer. And there is now no need to override drawRect:.

Resources