自定義ViewController

前言

為什么翻譯這系列文章

概述

你可以繼承UIViewController來展示的你的App的內(nèi)容义郑。大部分自定義的ViewController都是內(nèi)容型的ViewController,也就是說,它包含了所有的視圖,并負(fù)責(zé)為這些視圖提供數(shù)據(jù)。相反,容器型ViewController不擁有所有的視圖,它的部分子視圖被其他ViewController管理著劣领。自定義容器型ViewController和內(nèi)容型ViewController的步驟基本一樣,接下來我們會(huì)一一講到铁材。

對(duì)于內(nèi)容型ViewController尖淘,常見的分類有:

  • UITableViewController, 當(dāng)你的ViewController的主View是一個(gè)表格時(shí)使用UITableViewController。
  • UICollectionViewController著觉,當(dāng)你的ViewController的主View是一個(gè)集合性的視圖村生。
  • UIViewController,所有其他類型的視圖饼丘。

對(duì)于容器類型的ViewController趁桃,父類取決于你是否修改了已存在的容器類。對(duì)于已存在的容器性視圖控制器肄鸽,選擇一個(gè)你想要修改的卫病,對(duì)于新的容器型ViewController,你可以子類化UIViewController典徘。關(guān)于創(chuàng)建一個(gè)容器型ViewController蟀苛,請(qǐng)參考 Implementing a Container View Controller

實(shí)現(xiàn)UI

你可以使用storyboard來實(shí)現(xiàn)ViewController的UI效果。雖然你也可以代碼來實(shí)現(xiàn)UI布局逮诲,但是storyboard是將視圖控制器的內(nèi)容可視化并為不同的環(huán)境定制視圖層次的絕佳方式帜平。可視化的UI構(gòu)建可以快速看到構(gòu)建結(jié)果而不必編譯和運(yùn)行App梅鹦。

下圖展示了一個(gè)storyboad的例子裆甩,每個(gè)長方形區(qū)域表示一個(gè)ViewController和與之相關(guān)的視圖。兩個(gè)ViewController之間的箭頭表示它們之間的關(guān)系和segues. 關(guān)系將容器型ViewController與它的子ViewController連接在一起齐唆。Segues 表示兩個(gè)ViewController之間的轉(zhuǎn)換淑掌。

每個(gè)新建的工程都有一個(gè) main storyboard, 它通常已經(jīng)包含一個(gè)或者多個(gè)ViewController。你可以在storyboard上從控件庫中拖拽出一個(gè)新的ViewController添加到面板上蝶念。新建的ViewController初始狀態(tài)下沒有與之關(guān)聯(lián)的類抛腕,必須通過設(shè)置“Identity inspector”給它賦予一個(gè)類。

使用storyboard編輯器可以做以下的操作:

  • 為一個(gè)ViewController新增媒殉、編排担敌、配置視圖。
  • 連接outlet和action廷蓉,參考:Handling User Interactions全封。
  • 創(chuàng)建ViewController之間的關(guān)系和segues。參考: Using Segues桃犬。
  • 為不同的size classes 設(shè)置布局刹悴。
  • 為手勢(shì)來響應(yīng)視圖的交互操作。

如果沒有使用過storyboard構(gòu)建UI攒暇,你可以參考Start Developing iOS Apps Today這個(gè)教程來一步一步的學(xué)習(xí)土匀。

處理用戶交互

應(yīng)用程序的響應(yīng)者事件處理傳入的事件并采取適當(dāng)?shù)牟僮鳌1M管ViewController是響應(yīng)者對(duì)象形用,但它機(jī)會(huì)不直接處理事件就轧,ViewController通常采用如下幾種方式響應(yīng)用戶事件:

  • ViewController定義action方法處理高級(jí)事件。Action 方法表示:
    • 特定的動(dòng)作田度《视控件和視圖調(diào)用指定action方法來響應(yīng)特定的用戶操作。
    • 手勢(shì)镇饺。手勢(shì)識(shí)別器調(diào)用指定的方法來告知手勢(shì)的當(dāng)前狀態(tài)乎莉。使用你自己的ViewController來處理手勢(shì)狀態(tài)的改變或者對(duì)整個(gè)手勢(shì)做出響應(yīng)。
  • ViewController監(jiān)聽由系統(tǒng)或者其他對(duì)象發(fā)出的通知奸笤。上報(bào)通知變化是一種更新ViewController狀態(tài)的一種方式惋啃。
  • ViewController作為其他對(duì)象的數(shù)據(jù)源或者代理。ViewController經(jīng)常用來作為table和collection view的數(shù)據(jù)源揭保。你也可以用它作為一個(gè)對(duì)象的代理如“CLLocationManager”對(duì)象肥橙,它通過代理告知地理位置的變更。

響應(yīng)事件經(jīng)常涉及到更新視圖的內(nèi)容秸侣,這需要擁有要更新視圖的引用存筏。你可以在ViewController中定義要修改內(nèi)容的視圖的outlet。下面代碼味榛,自定義ViewController中包含兩個(gè)outlets和一個(gè)action方法椭坚。

@interface MyViewController: UIViewController  

@property (weak, nonatomic) IBOutlet UIButton *myButton;  
@property (weak, nonatomic) IBOutlet UITextField *myTextField;

- (IBAction)myButtonAction:(id)sender;

@end
class MyViewController: UIViewController {
    @IBOutlet weak var myButton : UIButton!
    @IBOutlet weak var myTextField : UITextField!
    
    @IBAction func myButtonAction(sender: id)
}

在你的storyboard中,記得將你的ViewController的outlets和action方法和相應(yīng)的是視圖相連接搏色。在你的storyboard連接的outlets和actions確保他們?cè)谝晥D在被加載之后配置好善茎。關(guān)于如何在Xib中創(chuàng)建outlet和action參考:Builder connections Help。 關(guān)于如何處理事件频轿,參考:Event Hanlding Guide for iOS垂涯。

在運(yùn)行時(shí)展示你的視圖

Storyboard使得加載和展示ViewController的視圖的流程非常簡單烁焙。UIKit在它需要的使用視圖的時(shí)候會(huì)自動(dòng)從Storyboard中加載。作為加載流程的一部分耕赘,UIKit執(zhí)行以下任務(wù):

  1. 使用Storyboard中的信息實(shí)例化View

  2. 連接所有的outlets和actions

  3. 將根視圖賦值給ViewController的view屬性

  4. 調(diào)用ViewController的awakeFromNib

    當(dāng)這個(gè)方法被調(diào)用的時(shí)候骄蝇,ViewController的特征集合還是空,視圖可能不在他們最終的位置上操骡。

  5. 調(diào)用ViewController的viewDidLoad方法

    使用此方法添加或者移除視圖九火,修改布局約束,加載視圖所需要使用的數(shù)據(jù)册招。

在將ViewController的視圖展示在屏幕之前岔激,UIKit提供了一些額外的機(jī)會(huì)可以在視圖展示到屏幕前后對(duì)視圖進(jìn)行更改。需要指出的是是掰,下面方法將會(huì)被調(diào)用虑鼎。

  1. 調(diào)用ViewController的viewWillApper:方法是你知道視圖即將展示在屏幕上。
  2. 更新視圖的layout冀惭。
  3. 將視圖展示在屏幕上震叙。
  4. 調(diào)用viewDidAppear方法當(dāng)視圖已經(jīng)展示在屏幕上。

當(dāng)你增加散休,移除或者修改視圖或者視圖的位置和大小媒楼,記得同時(shí)要修改相應(yīng)視圖上的約束。對(duì)視圖的層級(jí)結(jié)構(gòu)進(jìn)行布局相關(guān)的更改會(huì)使得UIKit將layout標(biāo)記為“dirty”戚丸。在下一次更新循環(huán)中划址,layout引擎會(huì)比較視圖的大小和位置,使用當(dāng)前的約束應(yīng)用于改變的視圖層級(jí)限府。

關(guān)于不適用Storyboard創(chuàng)建視圖的方法夺颤,參考:UIViewController Class Referencep

管理視圖布局

當(dāng)視圖的尺寸和位置發(fā)生改變胁勺,UIKit會(huì)更新你視圖的布局信息世澜。UIKit使用自動(dòng)布局引擎根據(jù)當(dāng)前的約束更新視圖。UIKit也可以讓其他感興趣的對(duì)象知道視圖的變化署穗,比如當(dāng)前正在展示的對(duì)象寥裂。

在布局處理的過程中,UIKit通過幾中方式通知你案疲,你可以執(zhí)行額外的與布局相關(guān)的操作封恰。使用這些通知來更新你的布局約束或者在在布局約束應(yīng)用之后做最終的調(diào)整。在布局期間褐啡,UIKit執(zhí)行以下操作來影響ViewController:

  1. 在需要的時(shí)候更新ViewController和它的視圖的特征集合诺舔。

  2. 調(diào)用viewWillLayoutSubviews方法。

  3. 調(diào)用當(dāng)前UIPresentationController的containerViewWillLayoutSubviews方法。

  4. 調(diào)用ViewController的根視圖的layoutSubViews方法低飒。

    該方法的默認(rèn)實(shí)現(xiàn)是使用可用的約束計(jì)算新的布局许昨。之后該方法調(diào)用所有子視圖的layoutSubviews方法。

  5. 將計(jì)算后的布局信息應(yīng)用到視圖上逸嘀。

  6. 調(diào)用ViewController的viewDidLayoutSubviews方法车要。

  7. 調(diào)用當(dāng)前UIPresentationController對(duì)的containerViewDidLayoutSubviews方法。

ViewController可以使用viewWillLayoutSubviews和viewDidLayoutSubViews方法執(zhí)行額外的更新操作來影響布局操作崭倘。在布局之前,你可以增加或者移除視圖类垫,改變視圖的大小或者位置司光,更新約束或者更新相關(guān)視圖的屬性。布局之后悉患,你可能會(huì)重新加載table的數(shù)據(jù)残家,更新視圖的內(nèi)容,或者對(duì)視圖的大小和位置做出最后的調(diào)整售躁。

這里有幾個(gè)有效管理視圖的提示:

  • 使用Auto Layout坞淮。使用autolayout創(chuàng)建的約束可以方便的將內(nèi)容在不同尺寸的屏幕上展示。
  • 利用底部可底部的布局指南陪捷。使用這些布局指南可以確保內(nèi)容始終可見回窘。頂部布局指南影響著狀態(tài)欄和導(dǎo)航欄的高度。同樣的市袖,底部的布局指南影響著tabbar和toolbar的高度啡直。
  • 記得在移除和添加視圖時(shí)更新約束。如果你動(dòng)態(tài)的增加和移除視圖苍碟,記得更新響應(yīng)的約束酒觅。
  • ViewController的視圖執(zhí)行動(dòng)畫操作的時(shí)候暫時(shí)移除視圖。當(dāng)視圖使用UIKit的CoreAnimation執(zhí)行動(dòng)畫時(shí)微峰,在動(dòng)畫執(zhí)行期間移除約束舷丹,動(dòng)畫執(zhí)行完成之后再將約束添加回來。還有如果在視圖執(zhí)行動(dòng)畫期間蜓肆,如果改變了視圖的位置和大小要更新約束颜凯。

有關(guān)展示控制器以及它在ViewController的結(jié)構(gòu)中所扮演的角色,參考:The Presentation and Transition Process

高效管理內(nèi)存

盡管內(nèi)存分配的工作是由你來決定的症杏,下表中列出了UIViewController關(guān)于內(nèi)存創(chuàng)建和銷毀的常用方法装获。大多數(shù)銷毀操作時(shí)移除強(qiáng)引用的對(duì)象±鞑可以將一個(gè)強(qiáng)引用對(duì)象置為nil來移除它穴豫。

任務(wù) 方法 描述
創(chuàng)建ViewController要使用
的數(shù)據(jù)
initialization 方法 自定義初始化方法
(無論是用init命名還是其他名字),
它的職責(zé)就是將你的視圖控制器置于
一個(gè)可用的良好狀態(tài)。使用這些方法創(chuàng)建
相應(yīng)的數(shù)據(jù)結(jié)構(gòu)精肃,以供對(duì)應(yīng)的操作使用秤涩。
分配或者加載視圖所使用的數(shù)據(jù) ViewDidLoad 使用ViewDidLoad方法加載你打算展示的
數(shù)據(jù)。該方法調(diào)用時(shí)司抱,你的視圖對(duì)象已經(jīng)
存在并且是可用狀態(tài)筐眷。
響應(yīng)系統(tǒng)低內(nèi)存的通知 didReceiveMemoryWaring 使用此對(duì)象銷毀ViewController中
非關(guān)鍵的數(shù)據(jù),盡可能的銷毀更對(duì)的數(shù)據(jù)
視圖ViewController的關(guān)鍵對(duì)象 dealloc 重寫該方法僅用于執(zhí)行ViewController
的最后一次清理操作习柠。系統(tǒng)會(huì)自動(dòng)清理掉
實(shí)例變量所存儲(chǔ)的變量和屬性匀谣,
所以你不需要手動(dòng)的釋放。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末资溃,一起剝皮案震驚了整個(gè)濱河市武翎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溶锭,老刑警劉巖宝恶,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異趴捅,居然都是意外死亡垫毙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門拱绑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來综芥,“玉大人,你說我怎么就攤上這事欺栗『梁郏” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵迟几,是天一觀的道長消请。 經(jīng)常有香客問我,道長类腮,這世上最難降的妖魔是什么臊泰? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮蚜枢,結(jié)果婚禮上缸逃,老公的妹妹穿的比我還像新娘。我一直安慰自己厂抽,他們只是感情好需频,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著筷凤,像睡著了一般昭殉。 火紅的嫁衣襯著肌膚如雪苞七。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天挪丢,我揣著相機(jī)與錄音蹂风,去河邊找鬼。 笑死乾蓬,一個(gè)胖子當(dāng)著我的面吹牛惠啄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播任内,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼撵渡,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了死嗦?” 一聲冷哼從身側(cè)響起姥闭,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎越走,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體靠欢,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡廊敌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了门怪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骡澈。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖掷空,靈堂內(nèi)的尸體忽然破棺而出肋殴,到底是詐尸還是另有隱情,我是刑警寧澤坦弟,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布护锤,位于F島的核電站,受9級(jí)特大地震影響酿傍,放射性物質(zhì)發(fā)生泄漏烙懦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一赤炒、第九天 我趴在偏房一處隱蔽的房頂上張望氯析。 院中可真熱鬧,春花似錦莺褒、人聲如沸掩缓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽崇渗。三九已至,卻和暖如春奕扣,著一層夾襖步出監(jiān)牢的瞬間绢记,已是汗流浹背扁达。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蠢熄,地道東北人跪解。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像签孔,于是被迫代替她去往敵國和親叉讥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容