0
votes

I found similar questions in this website but none of them solved my issue. Please carefully read the whole code. The setNeedsDisplay() function is not calling the draw(_ rect: CGRect) when I want to draw a line on MyView.

I created a view called "myView" in storyboard as sub View of "MyViewController" and created a IBOutlet to the view controller.

Then I created a class called "MyViewClass" and set it as the class of "myView" in storyboard.

I set the bool value drawLine to true and call function updateLine(), the problem is the setNeedsDispaly() is not triggering the draw(_ rect: CGRect) function.

import UIKit

class MyViewClass : UIView{

    var drawLine = Bool() // decides whether to draw the line
    func updateLine(){
        setNeedsDisplay()
    }
    override func draw(_ rect: CGRect) {
        if drawLine == true{
            guard let context = UIGraphicsGetCurrentContext() else{
                return
            }
            context.setLineWidth(4.0)
            context.setStrokeColor(UIColor.red.cgColor)
            context.move(to: CGPoint(x: 415 , y: 650))
            context.addLine(to: CGPoint(x:415 , y: 550))
            context.strokePath()
        }

    }
}
class myViewController:UIViewController {
    @IBOutlet weak var insideView: UIView!
    override func viewDidLoad() {
        super.viewDidLoad()


        // Do any additional setup after loading the view.
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let myViewInstance = MyViewClass()
        myViewInstance.drawLine = true
        myViewInstance.updateLine()
    }
}

I'm fairly new to Swift. Any help will appreciated. Thanks.

2
please have a look at this answer. I have tried it myself and it feels like if the view is not visible it will not call drawRect. Just confirm your that the view you are planning to update is visible when the set the drawLine bool to true. - chirag90
The view is never added to your view hierarchy therefore it will never get drawn. - Sulthan
can you tell me how do I add this to View Hierarchy, Do I just add the View to the main View? because I already do that. - John Xavier

2 Answers

1
votes

You have 2 issues:

  1. you're not giving the new view a frame so it defaults to zero width and zero height
  2. you're not adding the view to the view heirarchy

    let myViewInstance = MyViewClass(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height))
    myViewInstance.backgroundColor = .white  // you might want this a well
    myViewInstance.drawLine = true
    self.view.addSubview(myViewInstance)
    myViewInstance.updateLine()
    

A cleaner way to have your view redraw when a property (such as drawLine) is changed is to use a property observer:

var drawLine: Bool = true {
    didSet {
        setNeedsDisplay()
    }
}

That way, the view will automatically redraw when you change a property and then you don't need updateLine().

Note that setNeedsDisplay just schedules the view for redrawing. If you set this on every property, the view will only redraw once even if multiple properties are changed.


Note: viewDidLoad() would be a more appropriate place to add your line because it is only called once when the view is created. viewWillAppear() is called anytime the view appears so it can be called multiple times (for instance in a UITabView, viewWillAppear() is called every time the user switches to that tab).

0
votes

MyView class

class myView : UIView {
    var updateView : Bool = false {
        didSet {
            setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect) {
        print("in Draw")

    }

}

MyViewController

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let view = myView()
        view.updateView = true
    }
}

In the storyboard i had setup the view class as myView therefore its visible.

StoryBoard Image

Output Image

Hopefully this will help you.