Search code examples
iosswiftuiviewdrawuigraphicscontext

How to clear UIView?


I am working on a drawing app where the user draws something on a view. On the same view controller I would like to create a button that would erase everything that was on the view and give it a blank slate. How would I do this? I added all of my code that is attached to the uiview to draw the object.

 import uikit 
class ViewController: UIViewController {
@IBOutlet weak var jj: draw!

@IBAction func enterScore(_ sender: Any) {
    (view as? drawViewSwift)?.clear()

}}

enter image description here

import  UIKit


 struct stroke {
let startPoint: CGPoint
let endPoint:  CGPoint
let color: CGColor

  }
class drawViewSwift: subClassOFUIVIEW {

var isDrawing = false
var lastPoint : CGPoint!
var strokeColor : CGColor = UIColor.black.cgColor
var storkes = [stroke]()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard !isDrawing else {return}
    isDrawing = true
    guard let touch = touches.first else {return}
    let currentPoint = touch.location(in: self)

    lastPoint = currentPoint
    setNeedsDisplay()
}
 override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard isDrawing else {return}
    guard let touch = touches.first else {return}
    setNeedsDisplay()

    let currentPoint = touch.location(in: self)
    print(currentPoint)
    let sstroke = stroke(startPoint: lastPoint, endPoint: currentPoint, color: strokeColor)
    storkes.append(sstroke)

    lastPoint = currentPoint

}
 override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard isDrawing else {return}
    isDrawing = false
    guard let touch = touches.first else {return}
    let currentPoint = touch.location(in: self)
    let sstroke = stroke(startPoint: lastPoint, endPoint: currentPoint, color: strokeColor)
    storkes.append(sstroke)
    lastPoint = nil
    setNeedsDisplay()
    print(currentPoint)
}

private var clearing = false



func clear() {
    clearing = true
    setNeedsDisplay()
}

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

    defer { setNeedsDisplay() }
    let context = UIGraphicsGetCurrentContext()

    guard !clearing else {
        context?.clear(bounds)
        context?.setFillColor(backgroundColor?.cgColor ?? UIColor.clear.cgColor)
        context?.fill(bounds)
        storkes.removeAll()
        clearing = false
        return
    }
    context?.setLineWidth(10)
    context?.setLineCap(.round)
    for stroke in storkes {
        context?.beginPath()
        context?.move(to:stroke.startPoint)
        context?.addLine(to: stroke.endPoint)
        context?.setStrokeColor(stroke.color)
        context?.strokePath()
    }
}

func crase() {
    storkes = []
    strokeColor = UIColor.black.cgColor
    setNeedsDisplay()
}
  }
  class subClassOFUIVIEW: UIView {

override func awakeFromNib() {

    layer.shadowOpacity = 1
    layer.shadowOffset = CGSize(width: 1, height: 1)
    layer.shadowPath = CGPath(rect: bounds, transform: nil)
    layer.shadowPath = CGPath(rect: bounds, transform: nil)
}
  }

  class MyViewController : UIViewController {
override func loadView() {
    let view = drawViewSwift()
    view.backgroundColor = .white

    let button = UIButton()
    button.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
    button.setTitle("Clear", for: .normal)
    button.setTitleColor(.blue, for: .normal)
    button.addTarget(self, action: #selector(clear), for: .touchUpInside)
    view.addSubview(button)
    self.view = view
}

@objc func clear() {
    (view as? drawViewSwift)?.clear()
}
   }

Solution

  • You can add to your drawViewSwift class this code:

    private var clearing = false
    func clear() {
      clearing = true       
      setNeedsDisplay()
    }
    

    At this point your drawRect should change to clear the view:

    override func draw(_ rect: CGRect) {
      super.draw(rect)
    
      defer { setNeedsDisplay() }
      let context = UIGraphicsGetCurrentContext()
    
      guard !clearing else {
        context?.clear(bounds)
        context?.setFillColor(backgroundColor?.cgColor ?? UIColor.clear.cgColor)
        context?.fill(bounds)
        storkes.removeAll()
        clearing = false
        return
      }
      context?.setLineWidth(10)
      context?.setLineCap(.round)
      for stroke in storkes {
        context?.beginPath()
        context?.move(to:stroke.startPoint)
        context?.addLine(to: stroke.endPoint)
        context?.setStrokeColor(stroke.color)
        context?.strokePath()
      }
    }
    

    In the guard we will call the clerk method of the context which will reset the context to be at its initial state. This method will cause the context to redraw a transparent view. Since the view is now transparent we must redraw our canvas to be with a background color again. We do it by using the fill method after setting the fill color to be the background color of the view.

    At this point all it's remaining to do is to clear our strokes array and switch back the value of clearing to false so that we are ready to draw again.

    In your view controller, the clear button just have to call the clear method of this view.

    Try it in playground:

    //: A UIKit based Playground for presenting user interface
    
    import UIKit
    import PlaygroundSupport
    
    struct stroke {
      let startPoint: CGPoint
      let endPoint:  CGPoint
      let color: CGColor
    
    }
    class drawViewSwift: subClassOFUIVIEW {
    
      var isDrawing = false
      var lastPoint : CGPoint!
      var strokeColor : CGColor = UIColor.black.cgColor
      var storkes = [stroke]()
      override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard !isDrawing else {return}
        isDrawing = true
        guard let touch = touches.first else {return}
        let currentPoint = touch.location(in: self)
    
        lastPoint = currentPoint
        setNeedsDisplay()
      }
      override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard isDrawing else {return}
        guard let touch = touches.first else {return}
        setNeedsDisplay()
    
        let currentPoint = touch.location(in: self)
        print(currentPoint)
        let sstroke = stroke(startPoint: lastPoint, endPoint: currentPoint, color: strokeColor)
        storkes.append(sstroke)
    
        lastPoint = currentPoint
    
      }
      override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard isDrawing else {return}
        isDrawing = false
        guard let touch = touches.first else {return}
        let currentPoint = touch.location(in: self)
        let sstroke = stroke(startPoint: lastPoint, endPoint: currentPoint, color: strokeColor)
        storkes.append(sstroke)
        lastPoint = nil
        setNeedsDisplay()
        print(currentPoint)
      }
    
      private var clearing = false
      func clear() {
        clearing = true
        setNeedsDisplay()
      }
    
      override func draw(_ rect: CGRect) {
        super.draw(rect)
    
        defer { setNeedsDisplay() }
        let context = UIGraphicsGetCurrentContext()
    
        guard !clearing else {
          context?.clear(bounds)
          context?.setFillColor(backgroundColor?.cgColor ?? UIColor.clear.cgColor)
          context?.fill(bounds)
          storkes.removeAll()
          clearing = false
          return
        }
        context?.setLineWidth(10)
        context?.setLineCap(.round)
        for stroke in storkes {
          context?.beginPath()
          context?.move(to:stroke.startPoint)
          context?.addLine(to: stroke.endPoint)
          context?.setStrokeColor(stroke.color)
          context?.strokePath()
        }
      }
    
      func crase() {
        storkes = []
        strokeColor = UIColor.black.cgColor
        setNeedsDisplay()
      }
    }
    class subClassOFUIVIEW: UIView {
    
      override func awakeFromNib() {
    
        layer.shadowOpacity = 1
        layer.shadowOffset = CGSize(width: 1, height: 1)
        layer.shadowPath = CGPath(rect: bounds, transform: nil)
        layer.shadowPath = CGPath(rect: bounds, transform: nil)
      }
    }
    
    class MyViewController : UIViewController {
      override func loadView() {
        let view = drawViewSwift()
        view.backgroundColor = .white
    
        let button = UIButton()
        button.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
        button.setTitle("Clear", for: .normal)
        button.setTitleColor(.blue, for: .normal)
        button.addTarget(self, action: #selector(clear), for: .touchUpInside)
        view.addSubview(button)
        self.view = view
      }
    
      @objc func clear() {
        (view as? drawViewSwift)?.clear()
      }
    }
    // Present the view controller in the Live View window
    PlaygroundPage.current.liveView = MyViewController()