Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw signature in a UIView using Swift 5

Tags:

ios

swift

I have an UIView where I try to draw a signature. The functionality works but the issue is that my drawing start from 5 centimetres below my cursor and I don't know why. Here is a gif with my bug:

enter image description here

Here is my small project:DrawSignature

Here is my code for drawing:

struct Line {
    let strokeWidth: Float
    let color: UIColor
    var points: [CGPoint]
}

class Canvas: UIView {

    // public function
    fileprivate var strokeColor = UIColor.black
    fileprivate var strokeWidth: Float = 1

    func setStrokeWidth(width: Float) {
        self.strokeWidth = width
    }

    func setStrokeColor(color: UIColor) {
        self.strokeColor = color
    }

    func undo() {
        _ = lines.popLast()
        setNeedsDisplay()
    }

    func clear() {
        lines.removeAll()
        setNeedsDisplay()
    }

    fileprivate var lines = [Line]()

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        guard let context = UIGraphicsGetCurrentContext() else { return }

        lines.forEach { (line) in
            context.setStrokeColor(line.color.cgColor)
            context.setLineWidth(CGFloat(line.strokeWidth))
            context.setLineCap(.round)
            for (i, p) in line.points.enumerated() {
                if i == 0 {
                    context.move(to: p)
                } else {
                    context.addLine(to: p)
                }
            }
            context.strokePath()
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        lines.append(Line.init(strokeWidth: strokeWidth, color: strokeColor, points: []))
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let point = touches.first?.location(in: nil) else { return }
        guard var lastLine = lines.popLast() else { return }
        lastLine.points.append(point)
        lines.append(lastLine)
        setNeedsDisplay()
    }
}

And here is my ViewController:

class ViewController: UIViewController {

    // Interface Links
    @IBOutlet weak var signatureView: Canvas!

    override func viewDidLoad() {
        super.viewDidLoad()

        setupViews()

        signatureView.setStrokeColor(color: .black)
    }

    func setupViews(){

        signatureView.layer.borderWidth = 0.5
        signatureView.layer.borderColor = UIColor.black.cgColor
        signatureView.layer.cornerRadius = 10
    }

    @IBAction func clearBtnTapped(_ sender: UIButton) {

        signatureView.clear()
    }
}
like image 271
Flo Avatar asked Apr 29 '19 11:04

Flo


1 Answers

I fix it. Problem was at this line:

guard let point = touches.first?.location(in: nil) else { return }

Fix was:

guard let point = touches.first?.location(in: self) else { return }

like image 174
Flo Avatar answered Nov 10 '22 19:11

Flo