My swifts codes goal below is to be able to draw a straight line. When the uiview is touch the user can only draw 90 degrees above the initial point. The direction has already ben decided. So the user can just draw the line above the point that is touched. You can the gif below the line on the left is what my code does below. The line on the right is what I would like to acheive.
import UIKit
class ViewController: UIViewController{
var draw = Canvas()
override func viewDidLoad() {
super.viewDidLoad()
[draw].forEach {
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false}
}
override func viewDidLayoutSubviews() {
draw.backgroundColor = .clear
NSLayoutConstraint.activate ([
draw.bottomAnchor.constraint(equalTo: view.bottomAnchor),
draw.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.77, constant: 0),
draw.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1, constant: 0),
draw.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
])
}
}
struct ColoredLine {
var color = UIColor.black
var points = [CGPoint]()
var width = 5
}
class Canvas: UIView {
var strokeColor = UIColor.red
var strokeWidth = 5
func undo() {
_ = lines.popLast()
setNeedsDisplay()
}
func clear() {
lines.removeAll()
setNeedsDisplay()
}
var lines = [ColoredLine]()
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
lines.forEach { (line) in
for (i, p) in line.points.enumerated() {
if i == 0 {
context.move(to: p)
} else {
context.addLine(to: p)
}
}
context.setStrokeColor(line.color.cgColor)
context.setLineWidth(CGFloat(line.width))
context.strokePath()
context.beginPath()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
var coloredLine = ColoredLine()
coloredLine.color = strokeColor
coloredLine.width = strokeWidth
lines.append(coloredLine)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: self) else { return }
guard var lastLine = lines.popLast() else { return }
lastLine.points.append(point)
lines.append(lastLine)
setNeedsDisplay()
}
}
It is OK to manufacture the coordinates, Points consists of x and y.
Keeping the y, and done.
keep the first point for one touch event
manufacture the rest points, the x of new get points is irrelevant
and in
touchesEnd
andtouchesCancell
,firstPt = nil