UI篇-VC的生命周期以及UIView的layoutSubviews和drawRect方法

前言

看似常用的UIView,其實(shí)有很多不經(jīng)常用到的方法和應(yīng)該注意的機(jī)制,我是一個(gè)喜歡打破砂鍋問(wèn)到底的人,可是很多問(wèn)題在網(wǎng)上搜索不到答案,大部分的博客都是轉(zhuǎn)載相同的東西,所以我自己就新建 Dome,實(shí)際測(cè)試了一些數(shù)據(jù),得到了一些有用的東西,分享給大家,其中也用到了其它大神的理論和指點(diǎn),在此感謝。


viewController的生命周期

  • 單個(gè)viewController的生命周期

    initWithCoder:(NSCoder *)aDecoder:(如果使用storyboard或者xib)
    loadView:#加載view 會(huì)多次調(diào)用并且會(huì)使viewWillLayoutSubviews、viewDidLayoutSubviews不再執(zhí)行
    viewDidLoad:view加載完畢
    viewWillAppear:控制器的view將要顯示,
    viewWillLayoutSubviews:控制器的view將要布局子控件
    viewDidLayoutSubviews:控制器的view布局子控件完成
    viewDidAppear:控制器的view完全顯示
    viewWillDisappear:控制器的view即將消失的時(shí)候
    viewDidDisappear:控制器的view完全消失的時(shí)候
    
  • 多個(gè)viewControllers跳轉(zhuǎn)

    當(dāng)我們點(diǎn)擊push的時(shí)候首先會(huì)加載下一個(gè)界面然后才會(huì)調(diào)用界面的消失方法
    initWithCoder:(NSCoder *)aDecoder:ViewController2 (如果用xib創(chuàng)建的情況下)
    loadView:ViewController2
    viewDidLoad:ViewController2
    viewWillDisappear:ViewController1 將要消失
    viewWillAppear:ViewController2 將要出現(xiàn)
    viewWillLayoutSubviews ViewController2
    viewDidLayoutSubviews ViewController2
    viewWillLayoutSubviews:ViewController1
    viewDidLayoutSubviews:ViewController1
    viewDidDisappear:ViewController1 完全消失
    viewDidAppear:ViewController2 完全出現(xiàn)
    
  • 小結(jié):
    整個(gè)控制器聲明周期: viewDidLoad -> viewWillAppear -> viewWillLayoutSubviews -> viewDidLayoutSubviews -> viewDidAppear -> viewWillDisappear -> viewDidDisappear

  • 說(shuō)明

viewWillLayoutSubviews 在 viewWillAppear 之后 viewDidAppear 之前執(zhí)行,這個(gè)方法會(huì)被調(diào)用多次,如果在此創(chuàng)建視圖,可能會(huì)創(chuàng)建多個(gè),而且這個(gè)方法中執(zhí)行耗時(shí)操作依然會(huì)造成跳轉(zhuǎn)卡頓的問(wèn)題。
一個(gè)VC 在執(zhí)行viewWillDisappear 或者viewDidDisappear 方法時(shí)都是出棧之后才執(zhí)行的,也就是說(shuō) 已經(jīng)不在 self.navigationController 的viewControllers中了,而一個(gè) VC 執(zhí)行viewWillAppear 時(shí)必定是 self.navigationController 的 topViewController即棧頂?shù)囊晥D。
一個(gè)很常見(jiàn)的問(wèn)題,我們需要在VC被銷毀的時(shí)候處理一些事情,可是 viewWillDisappear 不管是入棧新的視圖還是出棧當(dāng)前視圖都會(huì)被調(diào)用,無(wú)法判斷,結(jié)合我之前說(shuō)的原理,我們可以利用下面這個(gè)方法判斷當(dāng)前VC是否是被出棧了。
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:YES];
if ([[self.navigationController viewControllers] containsObject:self ]) {
NSLog(@"TwoViewController 暫時(shí)消失");
}else
{
NSLog(@"TwoViewController 出棧了");
}
}

首先需要特別說(shuō)明的一點(diǎn)是:

在使用 VC繪制UI的時(shí)候,它不同于 UIView,UIView中 init方法調(diào)用后,UIView就已經(jīng)繪制好(初始化好了)。

但是在VC中,當(dāng)前UIView的是在 viewDidLoad 執(zhí)行后才初始化好的,所以我們會(huì)見(jiàn)到這樣一個(gè)Bug,在VC初始化語(yǔ)句后面調(diào)用 一個(gè) VC的繪制UI的方法,你會(huì)發(fā)現(xiàn)根本沒(méi)有效果,這就是因?yàn)?,VC中跟試圖的初始化是需要時(shí)間的,你在VC根試圖初始化之前調(diào)用繪制UI的方法當(dāng)然是不會(huì)有效果出現(xiàn)的。

UIView的setNeedsDisplay和setNeedsLayout方法。

首先兩個(gè)方法都是異步執(zhí)行的。setNeedsDisplay會(huì)調(diào)用 drawRect方法,這樣可以拿到UIGraphicsGetCurrentContext,就可以畫(huà)畫(huà)。
setNeedsLayout會(huì)默認(rèn)調(diào)用layoutSubViews,就可以處理子視圖中的一些數(shù)據(jù)。

綜上兩個(gè)方法都是異步執(zhí)行的,layoutSubviews方便數(shù)據(jù)計(jì)算,drawRect方便視圖重繪。UIView中方法的執(zhí)行順序大概是這樣的:

init 方法 >>屬性的set/get 方法>> layoutSubviews(當(dāng)然是要達(dá)到觸發(fā)條件)>>drawRect, 使用得當(dāng)可以在View的調(diào)用中起到很好的效果。

layoutSubviews在以下情況下會(huì)被調(diào)用:

1、init初始化不會(huì)觸發(fā)layoutSubviews。
2、addSubview會(huì)觸發(fā)layoutSubviews。
3、設(shè)置view的Frame會(huì)觸發(fā)layoutSubviews,當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化。
4、滾動(dòng)一個(gè)UIScrollView會(huì)觸發(fā)layoutSubviews。
5、旋轉(zhuǎn)Screen會(huì)觸發(fā)父UIView上的layoutSubviews事件。
6、改變一個(gè)UIView大小的時(shí)候也會(huì)觸發(fā)父UIView上的layoutSubviews事件。
7、直接調(diào)用setLayoutSubviews。

drawRect在以下情況下會(huì)被調(diào)用:

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

drawRect方法使用注意點(diǎn):

1、 **若使用UIView繪圖,只能在drawRect:方法中獲取相應(yīng)的contextRef并繪圖。如果在其他方法中獲取將獲取到一個(gè)invalidate 的ref并且不能用于畫(huà)圖**。**drawRect:方法不能手動(dòng)顯示調(diào)用,必須通過(guò)調(diào)用setNeedsDisplay 或 者 setNeedsDisplayInRect,讓系統(tǒng)自動(dòng)調(diào)該方法。強(qiáng)行調(diào)用也不會(huì)起作用的。**
2、**若使用calayer繪圖,只能在drawInContext: 中(類似魚(yú)drawRect)繪制**,或者在delegate中的相應(yīng)方法繪制。同樣也是調(diào)用setNeedDisplay等間接調(diào)用以上方法
3、**若要實(shí)時(shí)畫(huà)圖,不能使用gestureRecognizer,只能使用touchbegan等方法來(lái)掉用setNeedsDisplay實(shí)時(shí)刷新屏幕。**

值得注意的是:

viewWillAppear 嚴(yán)謹(jǐn)?shù)恼f(shuō)應(yīng)該是視圖將要達(dá)到棧頂時(shí)調(diào)用,不是每次視圖出現(xiàn)在屏幕時(shí)就會(huì)調(diào)用,一個(gè)很常見(jiàn)的現(xiàn)象是,home鍵后,再次啟動(dòng)程序,第一個(gè)出現(xiàn)的頁(yè)面的 viewWillAppear 是不回被調(diào)用的。

setNeedsDisplay和setNeedsLayout 詳解

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

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

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