UIView with UIBezierPath with reversing path - ios

I am trying to give some mask at bottom view using UIBezierPath with addCurve() method.
Expected Result
Current Output
What I have tried is:
viewHeader.backgroundColor = headerColor
let path = UIBezierPath()
let cpoint1 = CGPoint(x: 80, y: 160)
let cpoint2 = CGPoint(x: 280, y: viewHeader.Height + 50)
path.move(to:.init(x: 0, y: viewHeader.Height + 10))
path.addCurve(to: .init(x: viewHeader.Width, y: 205), controlPoint1: cpoint1, controlPoint2: cpoint2)
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.reversing().cgPath
shapeLayer.fillColor = headerColor?.cgColor
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = 1.0
viewHeader.layer.addSublayer(shapeLayer)

I hope it ll work for you, enjoy.
func drawLine() {
let headerColor = UIColor.red
let path = UIBezierPath()
let cpoint1 = CGPoint(x: viewHeader.frame.width/4, y: 160)
let cpoint2 = CGPoint(x: viewHeader.frame.width*3/4, y: viewHeader.frame.height + 50)
path.move(to:.init(x: 0, y: 0))
path.addLine(to:.init(x: 0, y: viewHeader.frame.height - 50))
path.addCurve(to: .init(x: viewHeader.frame.width, y: viewHeader.frame.height - 50), controlPoint1: cpoint1, controlPoint2: cpoint2)
path.addLine(to: CGPoint(x: viewHeader.frame.width, y: 0))
path.addLine(to: CGPoint(x: 0, y: 0))
path.close()
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.reversing().cgPath
shapeLayer.fillColor = headerColor.cgColor
shapeLayer.strokeColor = headerColor.cgColor
shapeLayer.lineWidth = 1.0
viewHeader.layer.addSublayer(shapeLayer)
}

Related

How to draw a line at the corner of a square with CAShapeLayer in Swift

I am developing a face recognition application of Vision library, and I am having trouble drawing lines with CAShapeLayer
here is the code after getting camera output:
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return
}
let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: imageBuffer, orientation: .leftMirrored, options: [:])
let faceDetectionRequest = VNDetectFaceLandmarksRequest(completionHandler: { (request: VNRequest, error: Error?) in
DispatchQueue.main.async {
self.faceLayers.forEach({ drawing in drawing.removeFromSuperlayer() })
if let observations = request.results as? [VNFaceObservation] {
for observation in observations {
let faceRectConverted = self.videoPreviewLayer.layerRectConverted(fromMetadataOutputRect: observation.boundingBox)
let faceRectanglePath = CGPath(rect: faceRectConverted, transform: nil)
let faceLayer = CAShapeLayer()
faceLayer.path = faceRectanglePath
faceLayer.fillColor = UIColor.clear.cgColor
faceLayer.strokeColor = UIColor.systemPink.cgColor
self.faceLayers.append(faceLayer)
self.cameraView.layer.addSublayer(faceLayer)
}
}
}
})
do {
try imageRequestHandler.perform([faceDetectionRequest])
} catch {
print(error.localizedDescription)
}
}
result
the problem I am facing when I want to draw a short line at the corner of the square
Thanks for all the support!
You can use this:
let thinLayer = CAShapeLayer()
thinLayer.path = CGPath(rect: rect, transform: nil)
thinLayer.strokeColor = UIColor.purple.cgColor
thinLayer.fillColor = UIColor.clear.cgColor
thinLayer.lineWidth = 1.0
view.layer.addSublayer(thinLayer)
let cornerWidth: CGFloat = 20.0
let topLeftBezierPath = UIBezierPath()
topLeftBezierPath.move(to: CGPoint(x: rect.origin.x, y: rect.origin.y + cornerWidth))
topLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x, y: rect.origin.y))
topLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x + cornerWidth, y: rect.origin.y))
let topRightBezierPath = UIBezierPath()
topRightBezierPath.move(to: CGPoint(x: rect.maxX, y: rect.origin.y + cornerWidth))
topRightBezierPath.addLine(to: CGPoint(x: rect.maxX, y: rect.origin.y))
topRightBezierPath.addLine(to: CGPoint(x: rect.maxX - cornerWidth, y: rect.origin.y))
let bottomRightBezierPath = UIBezierPath()
bottomRightBezierPath.move(to: CGPoint(x: rect.maxX, y: rect.maxY - cornerWidth))
bottomRightBezierPath.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
bottomRightBezierPath.addLine(to: CGPoint(x: rect.maxX - cornerWidth, y: rect.maxY))
let bottomLeftBezierPath = UIBezierPath()
bottomLeftBezierPath.move(to: CGPoint(x: rect.origin.x, y: rect.maxY - cornerWidth))
bottomLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x, y: rect.maxY))
bottomLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x + cornerWidth, y: rect.maxY))
func cornerLayer(with bezierPath: UIBezierPath) -> CAShapeLayer {
let shape = CAShapeLayer()
shape.path = bezierPath.cgPath
shape.lineWidth = 4.0
shape.strokeColor = UIColor.purple.cgColor
shape.fillColor = UIColor.clear.cgColor
shape.lineCap = .round
return shape
}
let topLeftShape = cornerLayer(with: topLeftBezierPath)
view.layer.addSublayer(topLeftShape)
let topRightShape = cornerLayer(with: topRightBezierPath)
view.layer.addSublayer(topRightShape)
let bottomRightShape = cornerLayer(with: bottomRightBezierPath)
view.layer.addSublayer(bottomRightShape)
let bottomLeftShape = cornerLayer(with: bottomLeftBezierPath)
view.layer.addSublayer(bottomLeftShape)
Where:
view is the UIView on which to add the layer, in your case it's cameraView.
rect is the full rect of the face, in your case it's faceRectConverted
customize to fulfill your needs (lineWidh, strokeColor, cornerWidth which might me proportional to the size of the rect?)
Sample in Playground:
func drawing() -> UIView {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
view.backgroundColor = .orange
let rect = CGRect(x: 50, y: 50, width: 200, height: 200)
let thinLayer = CAShapeLayer()
thinLayer.path = CGPath(rect: rect, transform: nil)
thinLayer.strokeColor = UIColor.purple.cgColor
thinLayer.fillColor = UIColor.clear.cgColor
thinLayer.lineWidth = 1.0
view.layer.addSublayer(thinLayer)
let cornerWidth: CGFloat = 20.0
let topLeftBezierPath = UIBezierPath()
topLeftBezierPath.move(to: CGPoint(x: rect.origin.x, y: rect.origin.y + cornerWidth))
topLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x, y: rect.origin.y))
topLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x + cornerWidth, y: rect.origin.y))
let topRightBezierPath = UIBezierPath()
topRightBezierPath.move(to: CGPoint(x: rect.maxX, y: rect.origin.y + cornerWidth))
topRightBezierPath.addLine(to: CGPoint(x: rect.maxX, y: rect.origin.y))
topRightBezierPath.addLine(to: CGPoint(x: rect.maxX - cornerWidth, y: rect.origin.y))
let bottomRightBezierPath = UIBezierPath()
bottomRightBezierPath.move(to: CGPoint(x: rect.maxX, y: rect.maxY - cornerWidth))
bottomRightBezierPath.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
bottomRightBezierPath.addLine(to: CGPoint(x: rect.maxX - cornerWidth, y: rect.maxY))
let bottomLeftBezierPath = UIBezierPath()
bottomLeftBezierPath.move(to: CGPoint(x: rect.origin.x, y: rect.maxY - cornerWidth))
bottomLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x, y: rect.maxY))
bottomLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x + cornerWidth, y: rect.maxY))
func cornerLayer(with bezierPath: UIBezierPath) -> CAShapeLayer {
let shape = CAShapeLayer()
shape.path = bezierPath.cgPath
shape.lineWidth = 4.0
shape.strokeColor = UIColor.purple.cgColor
shape.fillColor = UIColor.clear.cgColor
shape.lineCap = .round
return shape
}
let topLeftShape = cornerLayer(with: topLeftBezierPath)
view.layer.addSublayer(topLeftShape)
let topRightShape = cornerLayer(with: topRightBezierPath)
view.layer.addSublayer(topRightShape)
let bottomRightShape = cornerLayer(with: bottomRightBezierPath)
view.layer.addSublayer(bottomRightShape)
let bottomLeftShape = cornerLayer(with: bottomLeftBezierPath)
view.layer.addSublayer(bottomLeftShape)
return view
}
let drawn = drawing()
drawn
Output:

How to give oval shape to UIView with shadow

How to make uiview with oval shape at bottom side only with shadow
You need to use UIBezierPath for this. Here is an example (just need to play with the values):
let layer = CAShapeLayer()
layer.fillColor = UIColor.red.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.shadowRadius = 5
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.5
layer.shadowRadius = 2
view.layer.addSublayer(layer)
let path = UIBezierPath()
path.move(to: .zero)
path.addLine(to: CGPoint(x: view.frame.maxX, y: 0))
path.addLine(to: CGPoint(x: view.frame.maxX, y: 50))
path.addQuadCurve(to: CGPoint(x: 0, y: 50), controlPoint: CGPoint(x: view.frame.midX, y: 70))
path.close()
layer.path = path.cgPath
and result:

Insert CATextLayer inside UIBezierPath and rotate

In the following example I'm trying to insert a CATextLayer inside a UIBezierPath and rotate it -45 degrees.
class DiagonalView: UIView {
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
path.move(to: .init(x: rect.maxX, y: rect.midY + (rect.midY / 2.5)))
path.addLine(to: .init(x: rect.midX + (rect.midX / 2.5), y: rect.maxY))
path.addLine(to: .init(x: rect.midX - (rect.midX / 10.5), y: rect.maxY))
path.addLine(to: .init(x: rect.maxX, y: rect.midY - (rect.midY / 10.5)))
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor.black.cgColor
layer.addSublayer(shapeLayer)
let textlayer = CATextLayer.init()
textlayer.string = "iPhone X"
textlayer.fontSize = 12
textlayer.isWrapped = true
textlayer.foregroundColor = UIColor.white.cgColor
textlayer.frame = path.bounds
let degrees = -45.0
let radians = CGFloat(degrees * Double.pi / 180)
textlayer.transform = CATransform3DMakeTranslation(10, 50, 0)
textlayer.transform = CATransform3DMakeRotation(radians, 0.0, 0.5, 1.0)
layer.addSublayer(textlayer)
}
}
let containerView = DiagonalView(frame: CGRect(x: 0.0, y: 0.0, width: 140.0, height: 140.0))
containerView.backgroundColor = .red
PlaygroundPage.current.liveView = containerView
Although its not actually the result that I expected
Result
Expected
Any idea of what mistake I might have done with the code?
Thanks a lot for your time!

How to create dotted step indicator in swift 5(iOS)

I have a requirement like to draw a dotted step indicator in swift 5. I have searched for lot of tutorials on the same but I couldn't get the proper result. I need the step indicator which should be in vertical position(Top to Bottom). I have used the following code but it is coming wrongly when I run the app in iPad.
private func drawLinePath() {
//let linePath = UIBezierPath()
let path = UIBezierPath()
let centerX = self.frame.width / 2.0
let lineHeight = self.frame.height / 10
path.move(to: CGPoint(x: centerX, y: 0))
path.addLine(to: CGPoint(x: centerX, y: lineHeight))
path.move(to: CGPoint(x: centerX, y:lineHeight + 3))
path.addLine(to: CGPoint(x: centerX, y: lineHeight + 5))
path.move(to: CGPoint(x: centerX, y:lineHeight + 8))
path.addLine(to: CGPoint(x: centerX, y: lineHeight + 10))
path.move(to: CGPoint(x: centerX, y:lineHeight + 12))
path.addLine(to: CGPoint(x: centerX, y: lineHeight + 15))
path.move(to: CGPoint(x: centerX, y:lineHeight + 18))
path.addLine(to: CGPoint(x: centerX, y: lineHeight + 21 ))
path.move(to: CGPoint(x: centerX, y:lineHeight + 23))
path.addLine(to: CGPoint(x: centerX, y: lineHeight + 26))
path.move(to: CGPoint(x: centerX, y:lineHeight + 28))
path.addLine(to: CGPoint(x: centerX, y: lineHeight + 31))
path.move(to: CGPoint(x: centerX, y:lineHeight + 33))
path.addLine(to: CGPoint(x: centerX, y: lineHeight + 36))
path.move(to: CGPoint(x: centerX, y:lineHeight + 38))
path.addLine(to: CGPoint(x: centerX, y: lineHeight + 41))
self.path = path.cgPath
}
here is code working perfectly.
func drawLineFromPoint(start : CGPoint, toPoint end:CGPoint, ofColor lineColor: UIColor, inView view:UIView) {
//design the path
let path = UIBezierPath()
path.move(to: start)
path.addLine(to: end)
//design path in layer
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = lineColor.cgColor
shapeLayer.lineWidth = 4.0
shapeLayer.lineCap = .round
shapeLayer.lineDashPattern = [0.001,16]
shapeLayer.lineDashPhase = 4
view.layer.addSublayer(shapeLayer)
}
func drawLine() {
let frm1: CGRect = img1.frame
let frm2 : CGRect = img2.frame
drawLineFromPoint(start: CGPoint(x: frm1.origin.x + 12, y: frm1.origin.y + 25), toPoint: CGPoint(x: frm1.origin.x + 12, y: frm2.origin.y), ofColor: UIColor.black, inView: self.view)
}
override func viewDidLoad() {
super.viewDidLoad()
drawLine()
}
here is image
For that dotted path you can take UILabel and set text as '......' with your required font size and color. No need to draw any Bezier path. Just use UILabel.
take UIView for dashed line and use below code for line.
extension UIView {
func createDashedLine(from point1: CGPoint, to point2: CGPoint, color: UIColor, strokeLength: NSNumber, gapLength: NSNumber, width: CGFloat) {
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = color.cgColor
shapeLayer.lineWidth = width
shapeLayer.lineDashPattern = [strokeLength, gapLength]
let path = CGMutablePath()
path.addLines(between: [point1, point2])
shapeLayer.path = path
layer.addSublayer(shapeLayer)
}}
Now use it like below..
let topPoint = CGPoint(x: vw.frame.midX, y: vw.bounds.minY)
let bottomPoint = CGPoint(x: vw.frame.midX, y: vw.bounds.maxY)
vw.createDashedLine(from: topPoint, to: bottomPoint, color: .lightGray, strokeLength: 4, gapLength: 6, width: 2)
You can use StepIndicator pod for that, you can find example from this link
https://github.com/chenyun122/StepIndicator
let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize.init(width: 20, height: 40))
let layer = CAShapeLayer()
let path = UIBezierPath(roundedRect: rect, cornerRadius: 4)
layer.path = path.cgPath
layer.strokeColor = UIColor.gray.cgColor
layer.lineDashPattern = [3,3];
layer.backgroundColor = _CLEAR_COLOR.cgColor;
layer.fillColor = _CLEAR_COLOR.cgColor;
viewDottedLine.layer.addSublayer(layer);
Change rect values as per your view and lineDashPattern.
Hope that will work for you.

How to set Corner Radius to UIBezierPath

I have created following image by UIBezierPath using this code
//// Bezier Drawing
let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint(x: 360, y: 0))
bezierPath.addCurve(to: CGPoint(x: 360, y: 75), controlPoint1: CGPoint(x: 359.53, y: 30.5), controlPoint2: CGPoint(x: 359.91, y: 55.45))
bezierPath.addCurve(to: CGPoint(x: 360, y: 153.78), controlPoint1: CGPoint(x: 360.35, y: 153.21), controlPoint2: CGPoint(x: 360, y: 153.78))
bezierPath.addCurve(to: CGPoint(x: 180, y: 153.78), controlPoint1: CGPoint(x: 360, y: 153.78), controlPoint2: CGPoint(x: 271.2, y: 212.77))
bezierPath.addCurve(to: CGPoint(x: 0, y: 153.78), controlPoint1: CGPoint(x: 88.8, y: 94.8), controlPoint2: CGPoint(x: 0, y: 153.78))
bezierPath.addLine(to: CGPoint(x: 0, y: 0))
bezierPath.addLine(to: CGPoint(x: 360, y: 0))
UIColor.green.setFill()
bezierPath.fill()
now i want to give corner radius to TopLeft and TopRight of this following Image using Slider.
I have Tried Following code but it did not works for me.
var cornerPath = path
cornerPath = UIBezierPath(roundedRect:self.imgTop.bounds,
byRoundingCorners:[.topLeft, .topRight],
cornerRadii: CGSize(width: CGFloat(cornerRadius),
height: CGFloat(cornerRadius)))
path.lineWidth = 1.0
let maskLayer = CAShapeLayer()
maskLayer.path = cornerPath.cgPath
self.imgTop.layer.mask = maskLayer
let maskLayerTop = CAShapeLayer()
maskLayerTop.fillColor = UIColor.white.cgColor
maskLayerTop.backgroundColor = UIColor.clear.cgColor
maskLayerTop.path = pathTop?.cgPath
maskLayerTop.cornerRadius = CGFloat(cornerRadius)
//maskLayerTop.masksToBounds = true
maskLayerTop.shadowRadius = CGFloat(cornerRadius)
maskLayerTop.fillColor = UIColor.green.cgColor
maskLayerTop.shadowColor = UIColor.blue.cgColor
imgTop.layer.mask = maskLayerTop
I had also tried to applying corner radius to Image view but it did not work.i want corner radius like following image.
Please Help!
.
.
NOTE: I had already create one path to create following Image
before your let bezierPath = UIBezierPath() for curve add
var = cornerRadiudSize = CGSize(width: 50.0, height: 50.0) //this is your global variable that you can change based on the slider and then draw
let p = UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: cornerRadiudSize)
p.addClip()
PS: Instead of all corner set the corners you want
IOS 14, swift 5 version
let bezierPath = UIBezierPath(roundedRect: shareContainerView.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 4, height: 4))
let maskLayer = CAShapeLayer()
maskLayer.path = bezierPath.cgPath
shareContainerView.layer.mask = maskLayer

Resources