Circular crown with UIBezierPath - swift

I'am trying draw a circular crown with UIBezierPath. I can draw two circle with two diferent radius:
let bezierCrown = UIBezierPath()
bezierCrown.addArc(withCenter: center,
radius: raidus1,
startAngle: 0,
endAngle: CGFloat.pi*2,
clockwise: true)
bezierCrown.move(to: CGPoint(x: center.x+distancia2, y: center.y))
bezierCrown.addArc(withCenter: center,
radius: raidus2,
startAngle: 0,
endAngle: CGFloat.pi*2,
clockwise: true)
But when I fill:
UIColor.green.setFill()
bezierCrown.fill()
Everything is filled: image.
I want only the crown to be filled.

You need to set the fillRule to evenOdd
let center = CGPoint(x: 200, y: 400)
let raidus1:CGFloat = 100
let raidus2:CGFloat = 80
let bezierCrown = UIBezierPath()
bezierCrown.addArc(withCenter: center,
radius: raidus1,
startAngle: 0,
endAngle: CGFloat.pi*2,
clockwise: true)
bezierCrown.move(to: CGPoint(x: center.x+raidus2, y: center.y))
bezierCrown.addArc(withCenter: center,
radius: raidus2,
startAngle: 0,
endAngle: CGFloat.pi*2,
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = bezierCrown.cgPath
shapeLayer.fillColor = UIColor.blue.cgColor
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillRule = .evenOdd
view.layer.addSublayer(shapeLayer)

Related

Inner shadow for partial arc with Swift

I want to create an inner shadow for an arc but I get half of a circle instead of the shadow (see image below).
My code is:
let rect = self.bounds
let segmentArcPath = UIBezierPath()
segmentArcPath.addArc(withCenter: rect.center,
radius: (rect.height - insetShadow) / 2,
startAngle: -.pi/2,
endAngle: value * 2 * .pi - .pi/2,
clockwise: true)
shadowPath = segmentArcPath.cgPath
I have tried to add two paths (to not close the shadow), but without success:
let rect = self.bounds
let segmentArcPath = UIBezierPath()
segmentArcPath.addArc(withCenter: rect.center,
radius: (rect.height - insetShadow) / 2,
startAngle: internalStrokeStart,
endAngle: internalStrokeEnd,
clockwise: true)
let segmentArcPath2 = UIBezierPath()
segmentArcPath2.addArc(withCenter: rect.center,
radius: (rect.height - insetShadow) / 2 - 5,
startAngle: internalStrokeStart,
endAngle: internalStrokeEnd,
clockwise: false)
segmentArcPath.append(segmentArcPath2)
shadowPath = segmentArcPath.cgPath
How can I create a shadow as shown in the image above? Do you have any hints?
As recommended by #vacawama:
Only create one UIBezierPath. After drawng the outer arc, draw a 5
unit line towards the center of the arc, then call addArc to add the
inner arc to the same path
let rect = self.bounds
let outerRadius = (rect.height - insetShadow) / 2
let segmentArcPath = UIBezierPath()
segmentArcPath.addArc(withCenter: rect.center,
radius: outerRadius,
startAngle: internalStrokeStart,
endAngle: internalStrokeEnd,
clockwise: true)
let innerCircleRadius = outerRadius - 2
let startPointXInnerCircle = cos(internalStrokeEnd) * innerCircleRadius + rect.center.x
let startPointYInnerCircle = sin(internalStrokeEnd) * innerCircleRadius + rect.center.y
segmentArcPath.addLine(to: CGPoint(x: startPointXInnerCircle, y: startPointYInnerCircle))
segmentArcPath.addArc(withCenter: rect.center,
radius: innerCircleRadius,
startAngle: internalStrokeEnd,
endAngle: internalStrokeStart,
clockwise: false)
shadowPath = segmentArcPath.cgPath

Set position of outerBelowCircle CAShapeLayer in the center of View

I make a circle by using CAShapeLayer, and I want to set the center of it, in the center of the view. But the circle will be created exactly below the center line (see the screenshot), could anyone help me on this?
let circle = CAShapeLayer()
view.layer.addSublayer(circle)
circle.position = view.center
let circularPath = UIBezierPath(arcCenter: .zero, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
circle.path = circularPath.cgPath
I also change the way that for setting it in the center, but It doesn't work
circle.position = CGPoint(x: view.layer.bounds.midX, y: view.layer.bounds.midY)
Consider the following method according to your screenshot this method will resolve your issue.
func showCircle() {
let view = UIView()
let circle = CAShapeLayer()
view.layer.addSublayer(circle)
let positionX = view.center.x
let positionY = view.center.y - 100 // your circle radius
circle.position = CGPoint(x: positionX, y: positionY)
let circularPath = UIBezierPath(arcCenter: .zero, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
circle.path = circularPath.cgPath
}
I haven't tested the code. Please verify it by yourself.

How to crop the UIView as semi circle?

I want to crop UIView in semi circle shape
Thanks in advance.
A convenient way is just subclass a UIView, add a layer on it and make the view color transparent if it's not by default.
import UIKit
class SemiCirleView: UIView {
var semiCirleLayer: CAShapeLayer!
override func layoutSubviews() {
super.layoutSubviews()
if semiCirleLayer == nil {
let arcCenter = CGPoint(x: bounds.size.width / 2, y: bounds.size.height / 2)
let circleRadius = bounds.size.width / 2
let circlePath = UIBezierPath(arcCenter: arcCenter, radius: circleRadius, startAngle: CGFloat.pi, endAngle: CGFloat.pi * 2, clockwise: true)
semiCirleLayer = CAShapeLayer()
semiCirleLayer.path = circlePath.cgPath
semiCirleLayer.fillColor = UIColor.red.cgColor
layer.addSublayer(semiCirleLayer)
// Make the view color transparent
backgroundColor = UIColor.clear
}
}
}
This question was already answered here: Draw a semi-circle button iOS
This is a extract of that question but using a UIView:
Swift 3
let myView = [this should be your view]
let circlePath = UIBezierPath(arcCenter: CGPoint(x: myView.bounds.size.width / 2, y: 0), radius: myView.bounds.size.height, startAngle: 0.0, endAngle: CGFloat(M_PI), clockwise: true)
let circleShape = CAShapeLayer()
circleShape.path = circlePath.cgPath
myView.layer.mask = circleShape
Swift 4
let myView = [this should be your view]
let circlePath = UIBezierPath(arcCenter: CGPoint(x: myView.bounds.size.width / 2, y: 0), radius: myView.bounds.size.height, startAngle: 0.0, endAngle: .pi, clockwise: true)
let circleShape = CAShapeLayer()
circleShape.path = circlePath.cgPath
myView.layer.mask = circleShape
I hope this helps you
it works in swift 4 and swift 5 for this issue.
let yourView = (is the view you want to crop semi circle from top)
let circlePath = UIBezierPath(arcCenter: CGPoint(x: yourView.bounds.size.width / 2, y: yourView.bounds.size.height), radius: yourView.bounds.size.height, startAngle: 0.0, endAngle: .pi, clockwise: false)
let circleShape = CAShapeLayer()
circleShape.path = circlePath.cgPath
yourView.layer.mask = circleShape

How to change the endAngle programmatically

I would like to create an arc with Swift and SpriteKit by doing something like this:
func createArc(endAngle: CGFloat) -> SKShapeNode {
let bezierPath = UIBezierPath(arcCenter: CGPointMake(0, 0), radius: 300, startAngle: CGFloat(M_PI_2), endAngle: endAngle, clockwise: false)
let pathNode = SKShapeNode(path: bezierPath.CGPath)
pathNode.strokeColor = SKColor.blackColor()
pathNode.lineWidth = 50
pathNode.position = CGPoint(x: size.width/2, y: size.height/2)
pathNode.antialiased = true
return pathNode
}
But how should I change the endAngle value of the UIBezierPath programmatically say in the update() function?

Drawing shapes using UIBezierPath in swift

I dont know how to draw shape using UIBezierPath.Anyways i tried with lot of ways but did not successes.
I want to make the below shapes
Please help
func drawSliceInView(view: UIView, startAngle: CGFloat, endAngle: CGFloat, radius: CGFloat)
{
let centerPoint = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.width / 2)
let startValue = (startAngle * 2 * CGFloat(M_PI)) / 360 - CGFloat(M_PI_2)
let endValue = (endAngle * 2 * CGFloat(M_PI)) / 360 - CGFloat(M_PI_2)
let path = UIBezierPath(arcCenter: centerPoint, radius: radius, startAngle: startValue, endAngle: endValue, clockwise: true)
path.addLineToPoint(centerPoint)
path.closePath()
let sliceLayer = CAShapeLayer()
sliceLayer.path = path.CGPath
sliceLayer.fillColor = UIColor.blueColor().CGColor
sliceLayer.backgroundColor = nil
sliceLayer.strokeColor = UIColor.whiteColor().CGColor
sliceLayer.lineWidth = 2.0
view.layer.addSublayer(sliceLayer)
}
Usage example:
drawSliceInView(self.view, startAngle: -30, endAngle: 90, radius: 50)
drawSliceInView(self.view, startAngle: 90, endAngle: 210, radius: 50)