在這一章節(jié)中旭愧,你講學(xué)會(huì)如何在一個(gè)App里如果管理多個(gè)界面之間的跳轉(zhuǎn)颅筋,還將學(xué)會(huì)如何創(chuàng)建一個(gè)滾動(dòng)列表。
大多數(shù)的App都有多個(gè)界面和至少一個(gè)滾動(dòng)列表输枯。這章將會(huì)幫你構(gòu)建知識(shí)基礎(chǔ)议泵,有了這些知識(shí)儲(chǔ)備,你離著實(shí)現(xiàn)發(fā)布App這個(gè)目標(biāo)就更近了桃熄。
視圖控制器(View Controllers)
視圖控制器是MVC(Modl-View-Controller)模式的邏輯部分先口。可以去第一章快速?gòu)?fù)習(xí)一下MVC的知識(shí)瞳收。視圖控制器就是其字面的意思池充,這個(gè)控制器能夠控制某個(gè)視圖,不用過度思考缎讼。視圖能夠展示信息收夸,也能夠接收用戶的輸入。但是視圖不能做決定血崭,視圖控制器來做決定卧惜。
UIViewController
蘋果極力將MVC模式推薦給開發(fā)者,非常重視MVC夹纫,并且編寫了自己的控制器叫做UIViewController咽瓷,UIViewController是UIKit的一部分。UIKit是眾多能夠制作交互界面元素的類舰讹,如果你在某個(gè)類的開頭是UI茅姜,那么這個(gè)類屬于UIkit。UIViewController已經(jīng)幫你處理了很多編程時(shí)的臟活累活和體力活月匣,它有開箱即用的view property(視圖屬性)钻洒,這個(gè)視圖屬性被連接到一個(gè)視圖文件,大多數(shù)情況下锄开,是一個(gè)storyboard文件素标。
UIviewController也已經(jīng)為你提前寫好了一些方法。一些常見的事件萍悴,諸如視圖的載入和視圖的消失都已經(jīng)寫好了头遭,你可以把這些方法放到你自己的代碼中使用。
Page 135
總之癣诱,UIViewController提供了一些你需要的方法和屬性计维,這樣使UIViewController成為一個(gè)完美的父類,可以作為模板生成你自己的類撕予。
例如鲫惶,通常我們把UIViewController子類化,為了能夠運(yùn)行這個(gè)子類嗅蔬,在第一次運(yùn)行之前剑按,我們還需要添加一些代碼進(jìn)去:
class mySubController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad() // Do any addition setup after loading the view
}
}
看一下mySubController類中的viewDidLoad()
方法疾就,override關(guān)鍵詞告訴Xcode你要改變UIViewcontroller中默認(rèn)的viewDidLoad()
方法澜术,func關(guān)鍵詞聲明了這個(gè)方法艺蝴。viewDidLoad是你想從UIViewController中重寫的方法的名字。viewDidLoad()
方法沒有參數(shù)值鸟废,最后你要加一對(duì)大括號(hào)猜敢,大括號(hào)表示方法的開始和結(jié)束位置。
不管什么時(shí)候你想重寫一個(gè)方法盒延,代碼的第一行要調(diào)用super缩擂,super這個(gè)關(guān)鍵詞是用來表示目前這個(gè)類的父類。在這個(gè)例子中添寺,父類就是UIViewController胯盯。調(diào)用super是非常重要的一步,如果不調(diào)用super计露,在你的代碼被執(zhí)行之前博脑,viewDidLoad()
方法是不會(huì)做什么事情的,就好像你要建房子票罐,卻沒有先打地基叉趣。所以用?super.viewDidLoad()
來打地基,打好地基后该押,你就可以增加你自己的代碼:
class mySubController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any addition setup after loading the view
println("The View Has Loaded")
}
}
printlin方法調(diào)用后將會(huì)在Debugger中打印出一段信息"The View Has Loaded"疗杉。在編程時(shí),記著給每一個(gè)視圖控制器都配置一個(gè)視圖和控制器蚕礼,這是個(gè)好習(xí)慣烟具。
UINavigationController
直到現(xiàn)在,你編寫的App都只有一個(gè)界面奠蹬。然而净赴,現(xiàn)在iOS平臺(tái)上知名的App都有多個(gè)界面,能夠從左過渡到右邊罩润。例如玖翅,iPhone上的郵件App,當(dāng)你點(diǎn)擊一個(gè)郵件時(shí)割以,會(huì)滑動(dòng)到一個(gè)新的界面金度。
Page 136 | Chapter 5 : Building Multiscreen Apps
郵件App也有返回按鈕。這種從左到右的過渡效果是navigation controller創(chuàng)建的严沥。
一個(gè)UINavigationController可以在數(shù)組中支持多個(gè)UIViewController猜极。記著,數(shù)組是集合類型消玄,能夠按照某個(gè)順序存儲(chǔ)多個(gè)元素跟伏。導(dǎo)航控制器(navigation controller)的使用的排序機(jī)制叫做堆棧(stack)丢胚,按照先進(jìn)后出的原則排列元素。stack有些像是登機(jī)受扳,如果你第一個(gè)登上飛機(jī)携龟,走到飛機(jī)后面坐在靠窗的位置,那么在下飛機(jī)時(shí)勘高,你是最后一個(gè)離開飛機(jī)的峡蟋。這就是先進(jìn)后出原則在工作時(shí)的一個(gè)范例。
假設(shè)你第一個(gè)登上飛機(jī)华望,走到飛機(jī)后面坐在靠窗的位置蕊蝗,接著一個(gè)男性乘客登機(jī)坐在了你旁邊的位置,接著一位女性乘客登機(jī)赖舟,坐在了靠近走廊的位置蓬戚。那么當(dāng)離開飛機(jī)時(shí),先是這位女乘客立刻飛機(jī)宾抓,接著是男乘客子漩,最后才是你。堆棧按照相反的順序加載和卸載洞慎,加載的時(shí)候是由下到上痛单,卸載的時(shí)候是由上到下。
為了給navigation controller增加view controller劲腿,你首頁(yè)要把view controller push推到navigation controller的上面旭绒,push就相當(dāng)于第一個(gè)人正在登機(jī)。The item goes as far toward the bottom as possible, but does not pass the itemsinserted before it. (這句話不會(huì)翻譯焦人,靜等高手)挥吵。堆棧中最上面的view controller將被展示給用戶。為了能給用戶展示另外一個(gè)界面花椭,就把另外一個(gè)界面push到當(dāng)前的界面忽匈。
為了去掉當(dāng)前的界面,我們使用navigation controller中的pop功能矿辽。(push和pop在ios9中已經(jīng)被棄用了)pop是指從堆棧中移除最上面的元素丹允。在這個(gè)例子中,pop移除的是當(dāng)前展示的界面袋倔,然后回到之前的界面雕蔽。pop相當(dāng)于頭等艙的乘客,最后一個(gè)登機(jī)宾娜,第一個(gè)離開飛機(jī)批狐。
當(dāng)一個(gè)view在navigation controller中展示時(shí),會(huì)在這個(gè)view的頂部增加一個(gè)navigation bar前塔。這個(gè)navigation bar有三個(gè)主要的部分:左邊的UIBarButtonItem嚣艇,中間的titleView承冰,然后是右邊的UIBarButtonItem,UIBarButtonItem就像是一個(gè)典型的button食零,但是它是在UINavigationBar中困乒,UINavigationBar這個(gè)類用來生成navigation controller中的navigation bar,當(dāng)另外一個(gè)界面展示在navigation controller中時(shí)慌洪,左邊的UIBarButtonItem就會(huì)自動(dòng)變成一個(gè)返回按鈕顶燕。titleView展示UIViewController的title屬性值凑保,這里關(guān)鍵記著冈爹,title屬性值是由view controller定義的,但是是在navigation controller中顯示欧引。在view controller中設(shè)置title屬性非常簡(jiǎn)單:
title = " Countries"
每一個(gè)view controller都有title屬性频伤,因?yàn)閁IViewController定義了這個(gè)屬性。返回按鈕也會(huì)顯示要返回的界面的名字芝此。
View Controller | Page 137
最后憋肖,右邊的UIBarButtonItem是可選的,右邊這個(gè)位置可以放置一個(gè)主要或者次要的行為婚苹。例如設(shè)置按鈕可以放在App的右上角岸更。
Table View
滾動(dòng)視圖是iOS Apps中最常見的用戶界面。例如膊升,iPhone的設(shè)置怎炊,里面就有一個(gè)目錄滾動(dòng)視圖,當(dāng)用戶點(diǎn)擊某個(gè)選項(xiàng)時(shí)廓译,會(huì)跳到新的界面顯示更詳細(xì)的信息评肆。這個(gè)效果是結(jié)合了navigation controller和table views來實(shí)現(xiàn)的。navigation controller控制著目前顯示哪個(gè)界面非区,而table views則顯示滾動(dòng)視圖內(nèi)容瓜挽。
table view有幾個(gè)關(guān)鍵部分組成,滾動(dòng)視圖中的每一行叫做cell征绸,cell是用了展示table view中每行的內(nèi)容久橙。table view可以有很多個(gè)cell,多個(gè)cell組成section(組)管怠。sections是用來把行區(qū)分成不同的部分淆衷。在iPhone設(shè)置,就是用不同的section把目錄分開排惨,像是通知中心吭敢,控制中心,個(gè)人隱私暮芭。每個(gè)table view都有header和footer鹿驼,header是在cell上面欲低,footer在cell下面。
最后畜晰,一個(gè)table view有兩種style(風(fēng)格)砾莱。默認(rèn)風(fēng)格是Plain,一個(gè)緊挨著一個(gè)列出每一行凄鼻,另外一個(gè)風(fēng)格Grouped腊瑟,是把一組一組在一起,不同的組之間用空隙間隔块蚌。
Delegation
很多的體育網(wǎng)站或者是App都會(huì)提供一個(gè)提醒的服務(wù)闰非,當(dāng)你喜歡的球隊(duì)得分時(shí),就會(huì)往你的手機(jī)或者郵箱中發(fā)送提醒的消息峭范,比如不管什么時(shí)候舊金山巨人隊(duì)贏了全壘打财松,你都會(huì)收到震動(dòng)提醒。
類似的概念也應(yīng)用在了控制器的提醒功能上纱控,App內(nèi)部發(fā)生某個(gè)事件時(shí)辆毡,就會(huì)發(fā)出提醒。為某個(gè)事件訂閱或者接收提醒的過程叫做delegation(委托)甜害。委托一個(gè)delegate接收所有的通知舶掖。然而,delegate不只是只接受通知尔店,大多數(shù)情況下眨攘,delegate也必須回應(yīng)這些通知。
例如闹获,你要管理一個(gè)公司期犬,你告訴保安處監(jiān)視休息室,不管什么時(shí)候休息室的人數(shù)超過3個(gè)避诽,就讓保安敲你的門龟虎。敲門就是一個(gè)通知,在每次收到通知后沙庐,你可以選擇如何處理這些通知鲤妥。
當(dāng)一個(gè)table view第一次創(chuàng)建時(shí),需要回答一系列的問題后才能使用拱雏。table view讓delegate來接收問題并提供答案棉安。
Page 138 | Chapter 5 : Building Multiscreen Apps
例如,table view會(huì)問delegate要?jiǎng)?chuàng)建多少行铸抑,delegate必須用個(gè)具體的數(shù)字或者整型變量來回答這個(gè)問題贡耽。
實(shí)際上可以為每個(gè)需要知道的信息重寫方法就能回答一系列的問題。例如,問要有多少行蒲赂,你需要重新numberOfRowsInSection
方法:
override func tableView ( tableView: UITableView, numberOfRowsInSection section: Int ) -> Int {
//Return the number of rows in the section
return 10
}
如何看不懂方法名字阱冶,也沒有關(guān)系,關(guān)注方法里面的代碼就可以了滥嘴。在這個(gè)例子中木蹬,numberOfRowsInSection
方法返回了一個(gè)整型,返回的是10若皱,這樣table view就會(huì)有10行镊叁。這就是眾多必須回答的問題之一,回答完這些問題才能創(chuàng)建一個(gè)table view走触。
所有的問題都打包在一個(gè)協(xié)議(protocal)里晦譬。協(xié)議(protocal)以一種特定的方式做事。例如饺汹,機(jī)場(chǎng)的協(xié)議就是要檢查你的行李蛔添,通過安檢痰催,登機(jī)兜辞。這每一個(gè)步驟,你都要提供信息夸溶,如目的地是哪里逸吵。關(guān)鍵是你要完全同意協(xié)議中要求的事項(xiàng)。在編程時(shí)缝裁,這就叫做conforming(遵從協(xié)議)扫皱,表示你同意回應(yīng)協(xié)議中所有需要回應(yīng)的方法。
UITableViewController
UIViewController
同樣的捷绑,UITableViewController也是已經(jīng)為你創(chuàng)建table view做了大部分的臟活累活體力活韩脑。UITableViewController會(huì)自動(dòng)創(chuàng)建一個(gè)table view,然后設(shè)置tableView
屬性粹污,同時(shí)也需要委托自己獲取所有需要的delegate方法段多。
UITableViewDataSource
UITableView的delegate協(xié)議有三個(gè)必須要寫的方法,叫做UITableViewDataSource壮吩。這個(gè)協(xié)議包括組的數(shù)量进苍,美組中行的數(shù)量,以及cell如何展現(xiàn)鸭叙。
Delegation | Page 139
第一個(gè)方法是numberOfSectionsInTableView(_:)
觉啊,這個(gè)方法需要一個(gè)整型值,來作為table view中section組的數(shù)量沈贝。重寫這個(gè)方法非常簡(jiǎn)單:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
//#warning Potentially incomplete method implementation.
//return the number of sections.
return 0
}
注意到return那行目前是零杠人,這意味著這個(gè)table view中沒有組。蘋果公司增加了一個(gè)警告注釋,說如果組的個(gè)數(shù)是零嗡善,那么就不會(huì)顯示行市俊,組包含行cell,沒有了組section滤奈,行cell也就不會(huì)被顯示出來:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
//return the number of sections.
return 1
}
第二個(gè)方法是tableView(_:numberOfRowsInSection:)
摆昧,這個(gè)方法需要一個(gè)整型,決定了某個(gè)組里具體有多少行:
override func tableView(tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
//#warning Incomplete method implementation
// Return the number of rows in the section
return 0
}
注意到return后面是零蜒程,這意味著每個(gè)組里都沒有行绅你,所以蘋果公司增加了一個(gè)警告注釋,讓你重寫這個(gè)方法:
override func tableView(tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
//#warning Incomplete method implementation
// Return the number of rows in the section
return 5
}
最后第三個(gè)方法是tableView(:cellForRowAtIndexPath:)
昭躺,這個(gè)是和行cell有關(guān)忌锯。這個(gè)方法里有個(gè)參數(shù)值叫indexPath
,是一個(gè)NSIndexPath领炫。NSIndexPath有兩個(gè)屬性偶垮。
Page 140 | Chapter 5 : Building Multiscreen Apps
section組屬性的索引是當(dāng)前組,cell行屬性的索引是當(dāng)前行帝洪。記著索引是從零開始計(jì)數(shù)的:
- 第一組第一行的索引NSIndexPath是0,0似舵。
- 第一組第四行的索引NSIndexPath是0,3。
- 第三組第一行的索引NSIndexPath是2,0葱峡。
可以用點(diǎn)語法調(diào)用section和row屬性:
var currentRow = indexPath.row
var currentSection = indexPath.section
tableView(:cellForRowAtIndexPath:)
這個(gè)方法一開始會(huì)讓有些你灰心喪氣砚哗,不過不用擔(dān)心,因?yàn)檫^一會(huì)就會(huì)明白了砰奕。先值關(guān)注方法里面的代碼蛛芥,不要害怕犯錯(cuò)誤:
override func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell =tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
return cell
}
Cell reuse(cell 重復(fù)使用)
第一行先創(chuàng)建了一個(gè)名為cell的常量。cell等同于一個(gè)table view的一個(gè)離隊(duì)行(dequeued cells)军援。一個(gè)離隊(duì)的cell是一個(gè)不再使用的cell仅淑。就和真實(shí)的世界一樣,循環(huán)利用資源非常重要胸哥。當(dāng)table view有很多行涯竟,受屏幕限制能一次顯示出來的行數(shù)是有限的,這些還沒有顯示出來的行實(shí)際上還沒有創(chuàng)建出來烘嘱。當(dāng)這行滑出屏幕后昆禽,就進(jìn)入了回收箱。在新的行創(chuàng)建之前蝇庭,回收箱會(huì)檢查一下有沒有可回收利用的行醉鳖。正是因?yàn)閏ell的可重復(fù)使用,在使用之前先刪除之前的信息哮内,就變得格外重要了盗棵。
通過tableView
變量來訪問table view壮韭,dequeueReusableCellWithIdentifier
方法使用回收來的cell或者創(chuàng)建新的cell。dequeueReusableCellWithIdentifier
方法有兩個(gè)參數(shù)值:identifier
纹因,String類型喷屋,確認(rèn)具體哪一行,IndexPath
是NSIndexPath類型瞭恰,標(biāo)識(shí)具體位置屯曹。
cellForRowAtIndexPath方法用override開頭,因?yàn)檫@個(gè)方法是繼承自UITableViewController惊畏。有了override恶耽,可以重寫cellForRowAtIndexPath方法了。
Delegation | Page 141
func關(guān)鍵詞表示這是一個(gè)方法颜启。第一個(gè)tableView是這個(gè)方法名字的一部分偷俭。括號(hào)中有這個(gè)方法需要的參數(shù),第一個(gè)參數(shù)名字是tableView缰盏,是一個(gè)UITableView涌萤。cellForRowAtIndexPath是這個(gè)方法的名字,接下來的參數(shù)名字是indexPath口猜,是一個(gè)NSIndexPath负溪。最后,這個(gè)方法需要一個(gè)UITableViewCell作為返回值暮的。
一旦你成功創(chuàng)建cell笙以,接下來就是為cell設(shè)置屬性來展示你的數(shù)據(jù)。
UITableViewCell有5類主要屬性:
1.textLabel冻辩,屬于UILabel,展示主要信息拆祈;
2.detailTextLabel恨闪,屬于UILabel,展示副標(biāo)題放坏,這個(gè)label不總是出現(xiàn)的咙咽;
3.imageView,屬于UIImageView淤年,在cell的左邊顯示圖片钧敞;
4.accessoryView,顯示一個(gè)大于號(hào)麸粮;
5.contentView溉苛,空白cell,可自定義弄诲。
UITableViewCell有4種風(fēng)格(style)愚战,上面的5個(gè)屬性在不同的風(fēng)格下有可能被隱藏或者位置變化:
1.Default
左對(duì)齊的text label,可選的imageView,沒有detailTextLabel
2.Value1
左對(duì)齊的黑色字體的text label寂玲,一個(gè)更小的藍(lán)色字體右對(duì)齊
3.Value2
左側(cè)有個(gè)右對(duì)齊的藍(lán)色字體的text label塔插,右側(cè)有個(gè)左對(duì)齊的黑色字體的text label
4.Subtitle
左側(cè)左對(duì)齊的黑色字體的text label,接著是一個(gè)字體更小的左對(duì)齊灰色text label
在這一章節(jié)中拓哟,你已經(jīng)學(xué)會(huì)了在一個(gè)APP里管理多個(gè)界面想许,還學(xué)會(huì)了如何創(chuàng)建一個(gè)滾動(dòng)視圖,你的知識(shí)庫(kù)正在充盈断序,現(xiàn)在是時(shí)候把剛剛學(xué)會(huì)的東西應(yīng)用一下了伸刃,開始我們的Passport練習(xí)吧。
Page 142 | Chapter 5 : Building Multiscreen Apps