I am trying to draw a line with a smooth quadratic curve attached to its end. Therefore, I am using this code:
import Foundation
import UIKit
class IndicatingView: UIView {
var path: UIBezierPath!
override init(frame: CGRect) {
super.init(frame: frame)
}
func createLineWithCurve() {
path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 0, y: self.frame.height - self.frame.width))
path.addQuadCurve(to: CGPoint(x: self.frame.width, y: self.frame.height), controlPoint: CGPoint(x: 0, y: self.frame.height))
}
override func draw(_ rect: CGRect) {
self.createLineWithCurve()
path.lineWidth = 3
// Specify a border (stroke) color.
UIColor.purple.setStroke()
path.stroke()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And the output I get looks quite good already:
However, as you can see, the quad-curve is fatter than the normal line. Also, the quad-curve seems to be cut off at the bottom. How can I fix that? I want the path to be completely smooth without looking fatter at some points or being cut-off somehow.
Thanks in advance for your help :)
The problem is that your path is getting clipped by the bounds of the view. For example, in your vertical stroke starting at 0, 0
, half of the path’s vertical stroke will fall outside of the left edge of the view.
You should use insetBy(dx:dy:)
to inset the stroked path by half the line width, which will ensure the whole stroke will fall within the bounds
of the view. And then use minX
, maxX
, etc. of that resulting inset CGRect
to figure out the various CGPoint
for your path.
For example:
class IndicatingView: UIView {
func lineWithCurve() -> UIBezierPath {
let lineWidth: CGFloat = 3
let rect = bounds.insetBy(dx: lineWidth / 2, dy: lineWidth / 2)
let path = UIBezierPath()
path.lineWidth = lineWidth
path.lineCapStyle = .square
path.move(to: CGPoint(x: rect.minX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY - rect.width))
path.addQuadCurve(to: CGPoint(x: rect.maxX, y: rect.maxY), controlPoint: CGPoint(x: rect.minX, y: rect.maxY))
return path
}
override func draw(_ rect: CGRect) {
UIColor.purple.setStroke()
lineWithCurve().stroke()
}
}
That yields: