swiftsubclassuislidercgpointuigraphicscontext

Change line width with uislider in a subclass value


My code is trying to use a slide value to change the width of a line. Right now It is not working. I only want dont want lines drawn before the value is change to be effected only new lines after the value is changed.Look at vat number in class Canvas. Struct ColoredLine controls the color of the line.


    struct ColoredLine {
    var color = UIColor.black
    var points = [CGPoint]()
}


class ViewController: UIViewController {

    @objc func hhh() {
        canvas.number = Int(justinBiber.value)
    }

    var justinBiber = UISlider()
}

class Canvas: UIView {

       var strokeColor = UIColor.green
       var number = 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 }

            context.setLineWidth(number)
            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()
        }

    }

Solution

  • The line width is just another property of your line. Add that property to the ColoredLine struct:

    struct ColoredLine {
        var color = UIColor.black
        var width = 5
        var points = [CGPoint]()
    }
    

    Add a strokeWidth property to your Canvas class and update that when the slider value changes:

    class Canvas : UIView {
        var strokeWidth = 5
    
        ....
    }
    

    In touchesBegan(), add the current value of the strokeWidth to the coloredLine instance:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        var coloredLine = ColoredLine()
        coloredLine.color = strokeColor
        coloredLine.width = strokeWidth
        lines.append(coloredLine)
    }
    

    Then in draw(rect:) set the context's strokeWidth before drawing the line:

    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(line.width)
        context.strokePath()
        context.beginPath()
    }