-2

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()
}
   }
  • 1
    You aren't providing an useful details in your question. What view needs to be cleared? What needs to be cleared in that view? How was information put in the view to begin with? Please update your question (don't post comments) with more useful details. – rmaddy Jan 12 '18 at 22:09
  • @rmaddy I want the uiview to be completly clear from any drawing or anything changed from the original uiview. –  Jan 12 '18 at 22:15
  • 2
    But how have you added things to the view? Clearing is simply removing the things you have added – Paulw11 Jan 12 '18 at 22:25
  • There is drawing on the view. Someone wrote text over what used to be a blank canvas –  Jan 12 '18 at 22:30
  • 1
    A `UIView` does not draw anything. If your app supports drawing into a view, you must be using a custom subclass of UIView that allows drawing, and uses some mechanism for remembering what the user draws. (Perhaps your view has a `UIBezierPath` that it uses to save and draw a set of lines?) We can't tell you how to clear the contents of your view unless you tell us how your view saves drawn contents in the first place. – Duncan C Jan 12 '18 at 22:57
  • 1
    You've been asked not to comment and to update your question with more useful details. As it stands, there isn't enough information here for us to help you. Please provide details on how the content is added to the view as well as what you've already tried. – Kane Cheshire Jan 12 '18 at 22:57
  • @KaneCheshire I have done some more editing. Hope that helps –  Jan 13 '18 at 01:53
  • 1
    Three people asked *how* things were drawn on the view. As in, could you provide us the code? Without it, you surely can't expect us to be able to help you. For instance, are you using `draw(rect:)`? Is the drawings a subview? Sublayers? –  Jan 13 '18 at 03:55
  • @DuncanC I added my drawing code –  Jan 13 '18 at 22:01
  • So create an `IBAction` method that sets your view's `storkes` property back to an empty array: `myDrawingView.storkes = [stroke](); myDrawingView.setNeedsDisplay()`. – Duncan C Jan 13 '18 at 23:57
  • @Paulw11, the OP has finally posted enough information for us to be able to help him. Can you vote to re-open so we can answer? I posted a partial answer as a comment, but the thread is now answerable. – Duncan C Jan 13 '18 at 23:59
  • @ElTomato, can you vote to re-open? – Duncan C Jan 14 '18 at 00:00
  • @DuncanC I am having a problem with jj.storkes = [stroke]();. It says that draw has no member stroke. jj is my uiview. –  Jan 14 '18 at 02:56
  • Did you write `jj.storkes = [stroke]()` or `jj.storkes = stroke()`? The first form is what you want. Note that you should enter 2 lines rather than using a semicolon - I just can't put multiple lines of code in a comment on SO. – Duncan C Jan 14 '18 at 12:16
  • 1
    Note that data types like `stroke` should be capitalized in Swift, so it should be `Stroke`, not `stroke`. And why is your variable `storkes`? Is that a typo? – Duncan C Jan 14 '18 at 12:17
  • @rmaddy, the OP added enough information to make the question answerable. Can you vote to reopen? – Duncan C Jan 14 '18 at 12:19
  • @DuncanC .stroke is not working. I took a screenshot of my code and posted it in question above. Thanks again for help. –  Jan 14 '18 at 18:37
  • @DuncanC I think the problem is that the view controller that the uiview is in a different class then the class that the view controller is in. –  Jan 14 '18 at 19:50
  • @DuncanC the question is open for re answer. –  Jan 15 '18 at 16:51
  • @eltomato question is available to re answer. –  Jan 15 '18 at 16:52
  • you can use this library for it https://github.com/iTofu/LCPaintView – Jitendra Modi Jan 26 '18 at 10:32

3 Answers3

4

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()
Giuseppe Lanza
  • 3,519
  • 1
  • 18
  • 40
  • This looks like it will work but I just don't know how to call the function from another class. func clear is a different class than when the action button is. The uiview is in its own class which is drawViewSwift. –  Jan 25 '18 at 04:38
  • Check the playground I posted. That one is a working example of what you are trying to achieve – Giuseppe Lanza Jan 25 '18 at 08:28
  • So from what I can see you set the view of your view controller to be a `drawViewSwift` type. Correct? if so, you can just cast your view to be a `drawViewSwift` object and call the clear method on it: `(view as? drawViewSwift)?.clear()` in your button action. If you added your view to the mainView via interface builder you just need an outlet pointing to that view and call the clear method on it in your button action. – Giuseppe Lanza Jan 25 '18 at 11:47
  • The button which is in viewController class now has the button with (view as? drawViewSwift)?.clear() in it. The code loads and there are no errors but nothing is delete on the view when the button is pressed. Nothing changes when the button is pressed even though the code was added. –  Jan 26 '18 at 03:50
  • Maybe because in your case the main view is not of type drawViewSwift. As I said before, if you added the view of type drawViewSwift as subView using storyboard you need a reference to it with IBOutlet – Giuseppe Lanza Jan 26 '18 at 08:14
0

Your code to draw and to clear works. You should correct your viewController code and the layout structure you have choose. I think it's better to make a view dedicated to draw, so for example you could have 3 different objects to the main view, one for your label, another for your button and the last as your drawViewSwift. With this structure your main view can handle the constraints between objects and the other objects don't disturb the drawing (and obviusly the cleaning..):

Layout:

enter image description here

Output:

enter image description here

Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
-1

If number of strikes are high - Recommanded

If your strokes array is too big. I recommend to use below code

let rectangle = CGRect(x: 0, y: 0, width: self.height, height: self.height)

CGContextSetFillColorWithColor(context, UIColor.white.CGColor)
CGContextAddRect(context, rectangle)
CGContextDrawPath(context, .Fill)

If user hasn't drawn many strikes

Since you have all the current drawn strokes inside array strokes. below method will also work.

Just redraw above thus strokes with your view background color

override func clearView() {
    let context = UIGraphicsGetCurrentContext()
    context?.setLineWidth(10)
    context?.setLineCap(.round)
    for stroke in storkes {
    context?.beginPath()
    context?.move(to:stroke.startPoint)
    context?.addLine(to: stroke.endPoint)
    context?.setStrokeColor(UIColor.white.cgColor)
          // Assuming your background color is white
    context?.strokePath()
    }   

}

Saranjith
  • 11,242
  • 5
  • 69
  • 122