setNeedsDisplay() 没有调用 draw(_ rect: CGRect)

Posted

技术标签:

【中文标题】setNeedsDisplay() 没有调用 draw(_ rect: CGRect)【英文标题】:setNeedsDisplay() is not calling draw(_ rect: CGRect) 【发布时间】:2019-08-13 08:19:19 【问题描述】:

我在这个网站上发现了类似的问题,但没有一个能解决我的问题。请仔细阅读整个代码。当我想在 MyView 上画一条线时,setNeedsDisplay() 函数没有调用 draw(_ rect: CGRect)

我在情节提要中创建了一个名为“myView”的视图作为“MyViewController”的子视图,并为视图控制器创建了一个IBOutlet

然后我创建了一个名为“MyViewClass”的类,并将其设置为情节提要中的“myView”类。

我将布尔值drawLine设置为true并调用函数updateLine(), 问题是setNeedsDispaly() 没有触发draw(_ rect: CGRect) 函数。

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

我对 Swift 还很陌生。任何帮助将不胜感激。谢谢。

【问题讨论】:

请看看这个answer。我自己试过了,感觉如果视图不可见,它就不会调用drawRect。只需确认您计划更新的视图在将 drawLine 设置为 true 时可见。 视图永远不会添加到您的视图层次结构中,因此它永远不会被绘制。 你能告诉我如何将它添加到视图层次结构中,我只是将视图添加到主视图吗?因为我已经这样做了。 【参考方案1】:

您有 2 个问题:

    您没有为新视图提供 frame,因此它默认为零宽度和零高度

    您没有将视图添加到视图层次结构中

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

当属性(例如drawLine)发生更改时,让视图重绘的一种更简洁的方法是使用属性观察器:

var drawLine: Bool = true 
    didSet 
        setNeedsDisplay()
    

这样,当你改变一个属性时,视图会自动重绘,然后你就不需要updateLine()了。

注意setNeedsDisplay 只是安排视图重绘。如果你在每个属性上都设置了这个,即使多个属性被改变,视图也只会重绘一次。


注意: viewDidLoad() 将是添加行的更合适的位置,因为它仅在创建 view 时调用一次。 viewWillAppear() 会在view 出现的任何时候被调用,因此它可以被多次调用(例如在UITabView 中,viewWillAppear() 会在用户每次切换到该选项卡时被调用)。

【讨论】:

感谢@vacawama,这解决了我的问题。非常感谢。【参考方案2】:

MyView 类

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

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

    


我的视图控制器

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
    

在故事板中,我将视图类设置为 myView,因此它是可见的。

希望这会对你有所帮助。

【讨论】:

感谢您的精心回复,我是否必须为此视图制作 IBOutlet?或者我可以将子视图添加到这个视图类的实例中吗? @JohnXavier 我还没有发表观点。 再次感谢@chirag90,您的回答也正确,不胜感激。

以上是关于setNeedsDisplay() 没有调用 draw(_ rect: CGRect)的主要内容,如果未能解决你的问题,请参考以下文章

使用 drawRect、setNeedsDisplay 和 layoutSubViews

UIView setNeedsDisplay 没有效果?

setNeedsDisplay 只被调用一次

如果我经常调用 setneedsdisplay,drawrect 多久会被调用一次?这是为啥?

在 for 循环中调用 setNeedsDisplay

SetNeedsDisplay 不工作