前言:
setNeedsDisplay
異步執(zhí)行的。它會自動調(diào)用drawRect
方法锡搜,這樣可以拿到 UIGraphicsGetCurrentContext
,就可以繪制了瞧掺。而setNeedsLayout
會默認調(diào)用layoutSubViews
耕餐,處理子視圖中的一些數(shù)據(jù)。
一辟狈、開始
我定義了一個UIView的子類肠缔,用于演示使用setNeedsDisplay
,這個CircleView
子類會在draw(_ rect: CGRect)
方法內(nèi)簡單繪制一個圓哼转,它有一個顏色屬性明未,這是我們將要設(shè)置用來改變圓的顏色。
import UIKit
class CircleView: UIView {
var color:UIColor = UIColor.red
override func draw(_ rect: CGRect) {
let path = UIBezierPath(ovalIn: rect)
color.setFill()
path.fill()
}
}
注意: setNeedsDisplayInRect
相當(dāng)于setNeedsDisplay
壹蔓,除了它是指定視圖的特定矩形區(qū)域更新趟妥,而不是整個視圖需要顯示。
二佣蓉、配置屬性披摄、組件
應(yīng)用程序的下一部分是在故事板中配置一些UIKit組件亲雪,其中一個是CircleView
。
為了允許用戶更改顏色疚膊,我已經(jīng)定義了UIStepper
控件义辕,我還添加一個按鈕,這可讓我們使用步進值來調(diào)整CircleView
的顏色值寓盗。我不會詳細介紹如何配置storyboard灌砖,因為重點是了解setNeedsDisplay
@IBOutlet weak var stepper: UIStepper! //change value,default value is 120.
@IBOutlet weak var circleView: CircleView!
IBOutlets可以讓我們訪問circleView
,Stepper
傀蚌。對于步進值的變化基显,有IBActions,最后,有一個colorChangeBtn
喳张,它將調(diào)用一個未定義的方法changeColorFromStppers
方法续镇。該方法將收集步進器的值,使用它創(chuàng)建一個UIColor销部,并設(shè)置circleView
的color屬性摸航。
func changeColorFromStppers() {
let valueFloat = CGFloat(stepper.value)
let color = UIColor(red:valueFloat/255.0, green:valueFloat/255.0, blue:valueFloat/255.0, alpha:1.0)
circleView.color = color
}
在viewDidLoad中,根據(jù)故事板中配置的步進器的默認值舅桩,我觸發(fā)了一組初始的圓形顏色酱虎。該changeColorFromStppers
方法創(chuàng)建CGFloat
的用于步進數(shù)的值,創(chuàng)建的UIColor
擂涛,然后設(shè)置circleView.color
读串。
override func viewDidLoad() {
super.viewDidLoad()
self.changeColorFromStppers()
}
三、思考
現(xiàn)在更改stepper的值撒妈,然后點擊colorChangeBtn
按鈕恢暖,發(fā)現(xiàn)圓形顏色沒更新,這是什么原因呢狰右?
一般來說杰捂,使用框架控件,當(dāng)您設(shè)置屬性(如顯示標簽或值)時棋蚌,您將會使用該屬性嫁佳,這樣會導(dǎo)致重新繪制控件,因為系統(tǒng)會實現(xiàn)對控件
drawRect
方法的調(diào)用谷暮。而我們自定義了自己的UIView子類蒿往,所以我們需要處理影響顯示的控件的更新。在改變顏色的情況下湿弦,當(dāng)然需要我們自己控制重新繪制瓤漏。
根據(jù)上一篇文章setNeedsLayout和layoutIfNeeded看我就懂,所以我們在circleView.color = color
之后添加了對setNeedsLayout
或layoutIfNeeded
的調(diào)用,但結(jié)果同樣不會更新。類似地蔬充,旋轉(zhuǎn)設(shè)備也不會觸發(fā)重新繪制圓形俯在。這是因為視圖的緩存機制,即便視圖布局發(fā)生改變娃惯,也只是作為緩存。所以我們需要調(diào)用setNeedsDisplay
肥败,明確地告訴系統(tǒng)必須重新繪制趾浅,從而顯示新的顏色
由此,我們需要考慮三個重要的原則:
1馒稍、在iOS中皿哨,視圖很明顯會被緩存。通常纽谒,給定的視圖可能會被繪制一次证膨,同時也不需要更新。
2鼓黔、即使視圖可能被移動或者有另一個視圖重疊央勒,也可能不需要重新繪制,因此您不能僅僅依靠已經(jīng)移動整個視圖或添加另一個視圖基于setNeedsLayout
或updateIfNeeded
來導(dǎo)致重繪
3澳化、當(dāng)編寫重載drawRect
的UIView
子類時崔步,需要在需要重繪時指示給系統(tǒng)。因為drawRect
不能被手動調(diào)用缎谷,所以您需要使用setNeedsDisplay
方法告訴系統(tǒng)完成繪圖井濒,
四、添加setNeedsDisplay
所以接下來列林,我們需要添加setNeedsDisplay()
瑞你,有兩種方法
- 在
changeColorFromStppers
添加
完整代碼如下:
func changeColorFromStppers() {
let valueFloat = CGFloat(stepper.value)
let color = UIColor(red:valueFloat/255.0, green:100/255.0, blue:valueFloat/255.0, alpha:1.0)
circleView.color = color
//告訴系統(tǒng)需要重繪(Tell the system that circleView needs a redraw)
circleView.setNeedsDisplay()
}
- 在
CircleView
使用didSet
屬性觀擦器
代碼完整如下:
class CircleView: UIView {
var color:UIColor = UIColor.red {
didSet {
setNeedsDisplay() //告訴系統(tǒng)重繪界面
}
}
override func draw(_ rect: CGRect) {
let path = UIBezierPath(ovalIn: rect)
color.setFill()
path.fill()
}
}
這樣就能顯示了,希望大伙能多敲希痴,多體會者甲。
效果如下: