UIView的重繪及布局刷新

本文將簡要討論以下幾個問題:

1、UIViewdrawRect方法的調(diào)用機制及注意點
2、UIViewlayoutSubviews、layoutIfNeeded、setNeedsLayout等方法的調(diào)用機制
3、如何通過更新view的約束值來實現(xiàn)動畫效果

博客配圖

重繪機制 - drawRect

  • 方法定義

Drawing and Updating the View
-drawRect:
Draws the receiver’s image within the passed-in rectangle.
-setNeedsDisplay
Marks the receiver’s entire bounds rectangle as needing to be redrawn.
-setNeedsDisplayInRect:
Marks the specified rectangle of the receiver as needing to be redrawn.

- (void)drawRect:(CGRect)rect      //重寫此方法,執(zhí)行重繪任務

- (void)setNeedsDisplay               //標記為需要重繪,異步調(diào)用drawRect

- (void)setNeedsDisplayInRect:(CGRect)rect    //標記為需要局部重繪

重繪操作是在drawRect方法中完成,但是蘋果不建議直接調(diào)用drawRect方法,當然如果你強制直接調(diào)用此方法是沒有效果的。蘋果要求我們調(diào)用UIView類中的setNeedsDisplay方法,則程序會自動調(diào)用drawRect方法進行重繪。

  • 調(diào)用機制

drawRect調(diào)用是在Controller->loadView,Controller->viewDidLoad 兩方法之后調(diào)用的。所以不用擔心在控制器中,這些View的drawRect就開始畫了。這樣可以在控制器中設置一些值給View(如果這些View draw的時候需要用到某些變量值).
1、如果在UIView初始化時沒有設置rect大小,將直接導致drawRect不被自動調(diào)用。
2、該方法在調(diào)用sizeThatFits后被調(diào)用,所以可以先調(diào)用sizeToFit計算出size。然后系統(tǒng)自動調(diào)用drawRect:方法。(sizeToFit會自動調(diào)用sizeThatFits方法)
3、通過設置contentMode屬性值為UIViewContentModeRedraw。那么將在每次設置或更改frame的時候自動調(diào)用drawRect:
4、直接調(diào)用setNeedsDisplay,或者setNeedsDisplayInRect:觸發(fā)drawRect:,但是有個前提條件是rect不能為0
(以上1、2推薦,3、4不提倡)

  • drawRect方法使用注意點

1、 若使用UIView繪圖,只能在drawRect:方法中獲取相應的contextRef并繪圖。如果在其他方法中獲取將獲取到一個invalidate 的ref并且不能用于畫圖。drawRect:方法不能手動顯示調(diào)用,必須通過調(diào)用setNeedsDisplay 或 者 setNeedsDisplayInRect,讓系統(tǒng)自動調(diào)該方法。
2、若使用calayer繪圖,只能在drawInContext: 中(類似于drawRect)繪制,或者在delegate中的相應方法繪制。同樣也是調(diào)用setNeedDisplay等間接調(diào)用以上方法。
3、若要實時畫圖,不能使用gestureRecognizer,只能使用touchbegan等方法來調(diào)用setNeedsDisplay實時刷新屏幕
4、隨意使用drawRect可能引入內(nèi)存暴增的問題,參考內(nèi)存惡鬼drawRect

布局刷新

如果你的APP沒有用 Auto Layout,下面的方法可以實現(xiàn)手動 Layout
- (void)layoutSubviews    //對subviews重新布局

- (void)layoutIfNeeded    //如果有標記則立即重新布局

- (void)setNeedsLayout  //標記為需要重新布局
  • 調(diào)用機制

1、init初始化不會觸發(fā)layoutSubviews。

2、addSubview會觸發(fā)layoutSubviews。

3、設置view的Frame會觸發(fā)layoutSubviews,當然前提是frame的值設置前后發(fā)生了變化。

4、滾動一個UIScrollView會觸發(fā)layoutSubviews。

5、旋轉(zhuǎn)Screen會觸發(fā)父UIView上的layoutSubviews事件。

6、改變一個UIView大小的時候也會觸發(fā)父UIView上的layoutSubviews事件。

7、直接調(diào)用setNeedsLayout。

在蘋果的官方文檔中強調(diào):You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.
layoutSubviews, 當我們在某個類的內(nèi)部調(diào)整子視圖位置時,需要調(diào)用。
反過來的意思就是說:如果你想要在外部設置subviews的位置,就不要重寫。

  • 刷新子對象布局

- (void)layoutSubviews:這個方法,默認沒有做任何事情,需要子類進行重寫

- (void)setNeedsLayout: 標記為需要重新布局,異步調(diào)用layoutIfNeeded刷新布局,不立即刷新,但layoutSubviews一定會被調(diào)用

- (void)layoutIfNeeded:如果有需要刷新的標記,立即調(diào)用layoutSubviews進行布局(如果沒有標記,不會調(diào)用layoutSubviews

如果要立即刷新,要先調(diào)用[view setNeedsLayout],把標記設為需要布局,然后馬上調(diào)用[view layoutIfNeeded],實現(xiàn)布局
在視圖第一次顯示之前,標記總是“需要刷新”的,可以直接調(diào)用[view layoutIfNeeded]。

- (void)updateConstraintsIfNeeded:立即觸發(fā)約束更新,自動更新布局

- (void)updateConstraints:自定義view應該重寫此方法在其中建立constraints.
注意:要在實現(xiàn)最后調(diào)用[super updateConstraints]

- (BOOL)needsUpdateConstraints:constraint-based layout system使用此返回值去決定是否需要調(diào)用updateConstraints作為正常布局過程的一部分

- (void)setNeedsUpdateConstraints:當一個自定義view的某個屬性發(fā)生改變,并且可能影響到constraint時,需要調(diào)用此方法去標記constraints需要在未來的某個點更新,系統(tǒng)然后調(diào)用updateConstraints

UIView動畫

注意:如果你通過改變約束值來實現(xiàn)動畫效果,然而發(fā)現(xiàn)并沒有動畫,那可能是你沒有調(diào)用layoutIfNeeded方法。
舉個栗子:在ViewController的View上添加一個subView和button并添加相關(guān)約束,通過點擊button更改subView的約束值來實現(xiàn)動畫效果,代碼如下:

[UIView animateWithDuration:0.5 animations:^{
        self.leftConstr.constant = 200;//初始約束值為20
    } completion:nil];

上面的代碼是看不到動畫效果的,你應該這樣寫:

self.leftConstr.constant = 200;
    [UIView animateWithDuration:0.5 animations:^{
        [self.view layoutIfNeeded];
    } completion:nil];

這是因為self.leftConstr.constant = 200只執(zhí)行了setNeedsLayout方法標記了需要重新布局,但沒有立即執(zhí)行。相反,如果一些變化不想動畫,可以在動畫方法前執(zhí)行layoutIfNeeded方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容