简体   繁体   中英

setNeedsDisplay() is not calling draw(_ rect: CGRect)

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.

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).

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.

故事板图像

输出图像

Hopefully this will help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM