5

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()
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Flo
  • 429
  • 4
  • 13

1 Answers1

7

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 }

Flo
  • 429
  • 4
  • 13
  • Hello, how I can save the signature in an image? – Jose Tovar 27 secs ago Edit – Jose Tovar Jan 30 '20 at 21:11
  • Hi. You want to save the UIView as an UIImage ? – Flo Jan 30 '20 at 21:14
  • If the answer is yes, then you need to implement this function from here: https://stackoverflow.com/questions/4334233/how-to-capture-uiview-to-uiimage-without-loss-of-quality-on-retina-display/ – Flo Jan 30 '20 at 21:16
  • Hi is there a way I can add this UIVie inside scrollview without affecting the scrolling – MetaSnarf Mar 24 '22 at 07:20