swiftsubclasscgpointuigraphicscontextdidset

color of cgpoint changes all lines and should only change new lines


My code uses to classes. When the function dizzy is called it changes the color of all the lines in the uiview. What I want it to do is only change lines colors that are drawn after the function is called. It should not change the color of the lines that are already drawn like it does now.

class ViewController: UIViewController {
@objc func dizzy() {
     canvas.strokeColor = .gray

}

 var canvas = Canvas()
 }
  class Canvas: UIView {

    var strokeColor = UIColor.green {
          didSet {
              self.setNeedsDisplay()
          }
      }

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

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




var lines = [[CGPoint]]()

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

    guard let context = UIGraphicsGetCurrentContext() else { return }

   context.setStrokeColor(strokeColor.cgColor)
    context.setLineWidth(5)
    context.setLineCap(.butt)

    lines.forEach { (line) in
        for (i, p) in line.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([CGPoint]())
}

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.append(point)
    lines.append(lastLine)
    setNeedsDisplay()
}

}

Solution

  • You need to create a struct to store the color with the line. In touchesBegan(), store the current strokeColor with the coloredLine. In draw(rect:), for every line set the context.setStrokeColor(line.color.cgColor) before stroking the line.

    I tested this by adding buttons to change the colors. You can hook it up as you see fit.

    struct ColoredLine {
        var color = UIColor.black
        var points = [CGPoint]()
    }
    
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var canvas: Canvas!
    
        @IBAction func doRed(_ sender: UIButton) {
            canvas.strokeColor = .red
        }
    
        @IBAction func doGreen(_ sender: UIButton) {
            canvas.strokeColor = .green
        }
    
        @IBAction func doBlue(_ sender: UIButton) {
            canvas.strokeColor = .blue
        }
    
        @IBAction func doBlack(_ sender: UIButton) {
            canvas.strokeColor = .black
        }
    
     }
    
    
    class Canvas: UIView {
    
        var strokeColor = UIColor.green
    
        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 }
    
            context.setLineWidth(5)
            context.setLineCap(.butt)
    
            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.strokePath()
                context.beginPath()
            }
    
    
        }
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            var coloredLine = ColoredLine()
            coloredLine.color = strokeColor
            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()
        }
    
    }