Home > front end >  How to clear the background Color when context Line draw?
How to clear the background Color when context Line draw?

Time:01-18

I have UIView Canvas to draw lines.I am trying to clear the Canvas background color and show the image in the background each time the user draws a line. when I draw a line on Canvas, is not applying clear white background color. how do I solve the issue?

import UIKit

class Canvas: UIView{
    
    var lines = [[CGPoint]]()
    
    override func draw(_ rect:CGRect){
        super.draw(rect)
        guard let context  = UIGraphicsGetCurrentContext() else {
            return
        }
        context.setStrokeColor(UIColor.clear.cgColor)
        context.setLineWidth(20)
        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:nil) else {
            return
        }
        guard var lastLine =  lines.popLast() else { return }
        lastLine.append(point)
        lines.append(lastLine)
    
        setNeedsDisplay()
    }
}

class ViewController: UIViewController {
    
    let canvas  = Canvas()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(canvas)
        canvas.backgroundColor = .white
        canvas.frame = view.frame
    }
} 

CodePudding user response:

The trick is to draw the line paths with a special blend mode of clear. Here is an updated draw method that also makes use of UIBezierPath to make it a bit easier.

override func draw(_ rect: CGRect) {
    // Fill the canvas with the white background
    UIColor.white.set()
    let fill = UIBezierPath(rect: bounds)
    fill.fill()

    // Build a path with all of the lines
    let path = UIBezierPath()
    path.lineWidth = 20
    path.lineCapStyle = .butt

    for line in lines {
        for (i,p) in line.enumerated() {
            if i == 0 {
                path.move(to: p)
            } else {
                path.addLine(to: p)
            }
        }
    }

    // Draw the path with a clear color and a clear blending mode
    // This erases the white background showing whatever is behind the canvas
    UIColor.clear.set()
    path.stroke(with: .clear, alpha: 1)
}

You also need to remove the setting of the canvas view's backgroundColor property. Do not set it to any color.

Lastly, without any further changes you will end up with black lines instead of "erased" lines. The last change to fix this is to set isOpaque to false on the canvas view.

You can simply do:

canvas.isOpaque = false

in the view controller code but it's better to set this in the Canvas class. Do this by overriding the init methods.

override init(frame: CGRect) {
    super.init(frame: frame)

    isOpaque = false
}

required init?(coder: NSCoder) {
    super.init(coder: coder)

    isOpaque = false
}

Here's the updated viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(canvas)
    canvas.frame = view.frame
}

If you want to get fancy you can override backgroundColor in Canvas. This allows the creator of the canvas to set the desired background color but ensures that the actual canvas keeps a clear background color and uses the set color as the fill color.

private var fillColor: UIColor?

override var backgroundColor: UIColor? {
    get {
        return fillColor
    }
    set {
        fillColor = newValue
    }
}

Then update draw to use fillColor instead of hardcoding white.

(fillColor ?? .clear).set()

You might want a default color other than .clear.

  • Related