我認(rèn)為這是最好的建議:不斷的思考你怎樣才能把事情做得更好并且不斷的質(zhì)疑自己。
-Elon Musk,Tesla Motors
在前面一章,我們創(chuàng)建了一個(gè)簡(jiǎn)單的基于表格的app來(lái)用基本的單元格形式演示餐廳的清單绽快。這一章,我們將自定義表格單元格然后讓它看起來(lái)更時(shí)髦。我們將作出一些變化和增強(qiáng)功能:
- 用UITableViewController代替UITableView來(lái)重構(gòu)app粘驰。
- 給每個(gè)餐廳顯示獨(dú)特的圖片代替顯示同樣的縮略圖。
- 設(shè)計(jì)自定義的table view單元格代替基本樣式的table view單元格述么。
你可能想知道為什么我們要重構(gòu)同樣的app蝌数。做事情永遠(yuǎn)不止一種辦法。以前度秘,我們用UITableview來(lái)創(chuàng)建table view顶伞。在這章,我們將用UITableViewController來(lái)在Xcode里創(chuàng)建table view app剑梳。它更簡(jiǎn)單嗎唆貌?是的」敢遥回憶一下锨咙,我們需要采用UITableViewDataSource和UITableViewDelegate協(xié)議,UITableViewController已經(jīng)采用了這些協(xié)議并且為我們建立聯(lián)系追逮。除此之外酪刀,它有所有必須的布局約束粹舵。
Quick note: 我們正在構(gòu)建一個(gè)真正的app,所以我們給它一個(gè)更好的名字蓖宦。
創(chuàng)建一個(gè)Xcode工程齐婴,選擇Main.storyboard然后跳到界面編輯器。Xcode會(huì)生成默認(rèn)的視圖控制器稠茂。這次柠偶,我們不用默認(rèn)的控制器。選擇視圖控制器睬关,按delete鍵來(lái)刪除它诱担。這個(gè)視圖編輯器是與ViewController.swift關(guān)聯(lián)的。我們也不需要它电爹。在工程導(dǎo)航里蔫仙,選擇文件然后點(diǎn)擊delete按鈕。選擇”Move to Trash”丐箩。這將完全的刪除文件摇邦。
回到界面編輯器,從對(duì)象庫(kù)里拖曳一個(gè) Table View Controller(如 UITableViewController)屎勘,然后放在 storyboard里施籍。你必須指明這個(gè)控制器作為初始視圖控制器。這會(huì)告訴 iOS 這個(gè)table view 控制器是第一個(gè)被讀取的視圖控制器概漱。你需要做的是選擇 Attributes inspector丑慎,然后檢查 Is Initial View Controller 選項(xiàng)。你會(huì)看到一個(gè)箭頭指向table view控制器瓤摧。
我們還沒(méi)有插入任何數(shù)據(jù)到表格里竿裂。所以如果你編譯運(yùn)行 app,你將會(huì)看到一個(gè)空白的表格照弥。
默認(rèn)情況下腻异,table view 控制器與 UITableViewController 類(lèi)關(guān)聯(lián)在一起≌獯В回到工程導(dǎo)航欄然后右擊 FoodPin文件夾捂掰。選擇“New Files”來(lái)創(chuàng)建一個(gè)新的文件。
選擇 Source(在 iOS分類(lèi)下)> Cocoa Touch Class作為模板曾沈,然后點(diǎn)擊 Next这嚣。命名為新類(lèi) RestaurantTableViewController。因?yàn)槲覀冇靡粋€(gè) table view 編輯器工作塞俱,改變“Subclass of”值到 UITableViewController姐帚。保持其他的值不變,點(diǎn)擊“Next”然后把它保存到工程文件夾障涯。你應(yīng)該能看到 RestaurantTableViewController.swift文件在工程導(dǎo)航欄罐旗。
超類(lèi)和子類(lèi)
如果你是個(gè)編程新手膳汪,你可能想知道子類(lèi)是什么。Swift 是一個(gè)面向?qū)ο螅∣OP)語(yǔ)言九秀。在 OOP 里遗嗽,一個(gè)類(lèi)會(huì)被繼承到另一個(gè)類(lèi)。在這個(gè)實(shí)例中鼓蜒,RestaurantTableViewController類(lèi)繼承自 UITableViewController 類(lèi)痹换。它繼承 UITableViewController 類(lèi)所有的狀態(tài)和方法。RestaurantTableViewController 類(lèi)被稱(chēng)作 UITableViewController 的子類(lèi)都弹。換句話(huà)說(shuō)娇豫,UITableViewController 類(lèi)作為超類(lèi)(或者父類(lèi)(parent class))被 RestaurantTableViewController 繼承。
storyboard 里的table view controller不知道 RestaurantTableViewController 類(lèi)畅厢。所有我們必須分配給 table view controller新的自定義類(lèi)冯痢。進(jìn)到界面編輯器然后選擇 table view controller。在 Identity inspector 里框杜,設(shè)置自定義類(lèi)為 RestaurantTableViewController∑珠梗現(xiàn)在我們給storyboard 里的 table view controller和新類(lèi)建立了聯(lián)系。
還要做一件事來(lái)給 table view 進(jìn)行設(shè)置咪辱。選擇原型單元格椒振。在 Attributes inspector 里,改變格式為 Basic 然后設(shè)定 identifier 為 Cell梧乘。這和我們前一章做的很像。
OKay庐杨,用戶(hù)界面準(zhǔn)備好了选调。我們?nèi)ゴa字。在工程導(dǎo)航欄里選擇 RestaurantTableViewController.swift文件然后聲明一個(gè)實(shí)例變量灵份,用來(lái)放置表格內(nèi)容仁堪。
var restaurantNames = [“Cafe Deadend", "Homei", "Teakha", "Cafe Loisl", "Petite Oyster", "For Kee Restauran”,“ "Po's Atelier", "Bourke Street Bakery", "Haigh's Chocolate", "Palomino Espresso", "Upstate", "Traif", "Graham Avenue Meats", "Waffle & Wolf", "Five Leaves", "Cafe Lore", "Confessional", "Barrafina", "Donostia", "Royal Oak", "Thai Cafe”]
像之前說(shuō)的,UITableViewController 類(lèi)已經(jīng)添加了 UITableViewDataSource 和 UITableViewDelegate 協(xié)議填渠。作為 UITableViewController 的子集弦聂,RestaurantTableViewController 也添加了這些協(xié)議。
如果你沒(méi)忘記氛什,我們需要實(shí)現(xiàn)下面 UITableViewDataSource 協(xié)議要求的方法來(lái)提供表格內(nèi)容:
- tableView(_:numberOfRowsInSection:)
- tableView(_:cellForRowAtIndexPath:)
UITableViewController 類(lèi)為這兩個(gè)方法提供了一個(gè)默認(rèn)的執(zhí)行莺葫。通常,這些默認(rèn)的方法在我們的 app 里并不合適枪眉。我們需要重寫(xiě)默認(rèn)的方法然后提供我們自己的執(zhí)行捺檬。在 RestaurantTableViewController.swift 里插入以下的代碼:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cellIdentifier = “Cell”
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath)
//配置單元格
cell.textLabel?.text = restaurantNames[indexPath.row]
cell.imageView?.image = UIImage(named: “restaurant.jpg”)
return cell
}
在 Swift 里,為了重寫(xiě)一個(gè)超類(lèi)的方法贸铜,我們?cè)诜椒ǖ拈_(kāi)頭簡(jiǎn)單的增加 override 關(guān)鍵詞堡纬。以上的代碼和前一章一樣聂受,我不再?gòu)?fù)述細(xì)節(jié)了。
下一步烤镐,在 RestaurantTableViewController里改變下面的代碼片段蛋济。這些代碼是當(dāng)生成了類(lèi)文件時(shí) Xcode 自動(dòng)創(chuàng)建的。默認(rèn)情況下炮叶,章節(jié)數(shù)和章節(jié)行數(shù)都返回0值碗旅。換句話(huà)說(shuō),它告訴 table view說(shuō) table view 里面沒(méi)有數(shù)據(jù)悴灵。這不是我們想要的扛芽,所以我們必須把代碼改成這樣:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section:Int) ->Int {
return restaurantNames.count
}
這里我們告訴table view這里只有一章然后在數(shù)組里保存返回餐廳的數(shù)量。作為附注积瞒,numberOfSectionsInTableView 方法是可選的川尖。如果你移動(dòng)它,table view 仍然會(huì)工作茫孔,因?yàn)檎鹿?jié)數(shù)默認(rèn)設(shè)置成1叮喳。
最后横辆,下載圖片然后拖曳所有圖片到 Assets.xcassets文件夾≈侨拢現(xiàn)在,點(diǎn)擊“Run”按鈕然后你的 FoodPin app 看起來(lái)和我們之前構(gòu)建的一樣洋满。
現(xiàn)在你應(yīng)該理解怎樣在一個(gè) table view 里顯示數(shù)據(jù)剩晴。我已經(jīng)給你展示了兩個(gè)辦法:
1锣咒、用 UITableView 和 View Controller。
2赞弥、用 UITableViewController毅整。
你可能想知道你應(yīng)該用哪個(gè)辦法。大體來(lái)說(shuō)绽左,2#辦法更好悼嫉。UITableViewController 為你配置了所有事情。你可以簡(jiǎn)單的重寫(xiě)一些方法來(lái)提供表格數(shù)據(jù)拼窥。但是這樣失去了靈活性戏蔑。嵌入在 UITableViewController 里的 table view 是固定的,你不能改變它鲁纠。如果你想要用 table view布局一個(gè)更復(fù)雜的 UI总棵,1#方法將會(huì)更合適。
演示不同的縮略圖
你做了前面章節(jié)的練習(xí)嗎改含?我希望你已經(jīng)用功了彻舰。有很多方法來(lái)演示不同的縮略圖對(duì)應(yīng)每個(gè)表格行。我會(huì)給你展示最直白的方法。首先刃唤,下載圖片包隔心。添加所有的圖片到 Assets.xcasset。如果你喜歡尚胞,你可以使用你自己的圖片硬霍。
在我們改變代碼之前,讓我們重溫在表格行里顯示縮略行的代碼笼裳。
cell.imageView?.image = UIImage(named: “restaurant.jpg”)
上面那行代碼tableView(_:cellForRowAtIndexPath:) 方法指導(dǎo) UITableView 來(lái)在每個(gè)單元格里演示 restaurant.jpg唯卖。為了顯示不同的圖片,我們需要更改代碼行躬柬。
像之前解釋的那樣拜轨,iOS 每次調(diào)用這個(gè)方法,特殊的表格行將會(huì)顯示出來(lái)允青。正確的行數(shù)被嵌入到 indexPath 參數(shù)橄碾。你可以簡(jiǎn)單的使用 indexPath.rou 來(lái)找出哪一行正在處理。
因此颠锉,為了在每行顯示不同的圖片法牲,我們需要做的是添加一個(gè)新的數(shù)組來(lái)儲(chǔ)存縮略圖的文件名。我們把這個(gè)數(shù)組命名為 restaurantImages琼掠。插入下面這行代碼到 RestaurantTableViewController 類(lèi):
var restaurantImages = ["cafedeadend.jpg", "homei.jpg", "teakha.jpg", "cafeloisl.jpg", "petiteoyster.jpg", "forkeerestaurant.jpg", "posatelier.jpg", "bourkestreetbakery.jpg", "haighschocolate.jpg", "palominoespresso.jpg", "upstate.jpg", "traif.jpg", "grahamavenuemeats.jpg", "wafflewolf.jpg", "fiveleaves.jpg", "cafelore.jpg", "confessional.jpg", "barrafina.jpg", "donostia.jpg", "royaloak.jpg", "thaicafe.jpg”]
在上面的代碼里拒垃,我們用一個(gè)圖片文件名清單初始化了 restaurantImages 數(shù)組。圖片的順序與 restaurantNames 保持一致瓷蛙。
為了讀取相應(yīng)的餐廳圖片悼瓮,把 tableview(_:cellForRowAtIndexPath:)方法的代碼行改成:
cell.imageView?.image = UIImage(named:restaurantImages[indexPath.row])
保存所有改變以后,嘗試再次運(yùn)行你的 app艰猬。每個(gè)餐廳有它自己圖片横堡。
自定義 table view 單元格
app 是不是看起來(lái)更好了?我們用自定單元格來(lái)讓它變得更好姥宝。到目前為止我們利用的是默認(rèn)的 table view 單位格】制#縮略圖的位置和大小都是固定的腊满。如果你想要:
- 改變單元格的高度。
- 把縮略圖變大一點(diǎn)培己。
- 顯示更多餐廳的信息碳蛋,比如位置和類(lèi)型。
- 改變字體類(lèi)型和大小省咨。
- 顯示圓形的圖片來(lái)代替方形的圖片肃弟。
為了讓你更好的理解單元格是怎樣自定義的,看下圖,單元格看起來(lái)很酷笤受,對(duì)吧穷缤?
在界面編輯器里設(shè)計(jì)原型單元格(prototype cell)
prototype cell的美妙之處在于,它允許開(kāi)發(fā)者在 table view controller 里來(lái)自定義單元格箩兽。
我們先來(lái)改變單元格的樣式津肛。當(dāng)它設(shè)置成 Basic 樣式的適合你不能自定義單元格。在 Attributes inspector 里選擇原型單元格然后把樣式從 Basic 變成 Custom汗贫。
為了容納更大的縮略圖身坐,我們必須把單元格也變大一點(diǎn)。你需要改變table view 和原型單元格的行高落包。選擇 table view 然后把行高變成80部蛇。
然后選擇prototype cell,進(jìn)入 Size inspector咐蝇。檢查 custom 復(fù)選框然后把行高變成80涯鲁。
變更行高之后,從對(duì)象庫(kù)里拖一個(gè) Image View 到prototype cell嘹害。選擇 image view撮竿,點(diǎn)擊“Size”inspector,改變“X”笔呀,“Y”幢踏,“Width”和“height”的屬性。
接下來(lái)许师,我們添加三個(gè)標(biāo)簽到prototype cell:
- Name - 餐廳名字
- Lcation - 餐廳地址(如:紐約)
- Type - 餐廳形式(如:茶館)
為了添加一個(gè)標(biāo)簽房蝉,從對(duì)象庫(kù)里拖曳一個(gè) Label 對(duì)象到單元格。給第一個(gè)標(biāo)簽命名為“Name”微渠。我們用一個(gè)文本樣式(text style)來(lái)代替標(biāo)簽的系統(tǒng)字體搭幻。下一章我會(huì)給你解釋固定字體和文本樣式的區(qū)別。現(xiàn)在逞盆,進(jìn)入 Attributes inspector檀蹋,把字體改成 Txet Style - Headline。
拖曳另一個(gè)標(biāo)簽到單元格然后把它命名為 Location云芦。把字體樣式改成 Light 然后設(shè)置字體大小為14俯逾。同樣的設(shè)置字體顏色為 Dark Gray。最后舅逸,創(chuàng)造另一個(gè)標(biāo)簽命名為 Type桌肴。同樣的,把字體形式改成 Light 然后設(shè)置字體大小為13琉历。
我已經(jīng)在第六章介紹過(guò) stack views坠七。你不僅僅可以在 view controller 里用 stack view水醋,你同樣在 prototype cell 里使用 stack views 來(lái)布局約束。因此彪置,我們將用 stack views 來(lái)管理標(biāo)簽和圖片視圖拄踪,而不是定義布局約束。首先悉稠,按住 command 鍵宫蛆,選擇三個(gè)標(biāo)簽。點(diǎn)擊布局欄里的 stack 按鈕來(lái)把他們嵌入到垂直的 stack view 里的猛。進(jìn)入到 Attributes inspector耀盗,把 stack view 的間距從0改成1。這會(huì)在標(biāo)簽之間添加一個(gè)約束卦尊。
現(xiàn)在選擇我們剛創(chuàng)建的 image view 和 stack view叛拷。點(diǎn)擊 Stack 按鈕,界面編輯器將把它們嵌入到一個(gè)水平 stack view岂却。默認(rèn)情況下忿薇,image view 和“Label”stack view 之間沒(méi)有間距。你可以到 Attributes inspector 里把 spcing 選項(xiàng)從0改成10躏哩。很酷署浩,對(duì)嗎?你可以嵌套堆棧視圖來(lái)創(chuàng)建一些復(fù)雜的布局扫尺。
但是筋栋,這不意味著你不需要用 auto layout。我們?nèi)匀恍枰獮?stack view 來(lái)定義布局約束正驻。下圖描述了單元格的布局要求弊攘。
簡(jiǎn)而言之,我們希望單元格內(nèi)容(如 stack view)受限于單元格的可視區(qū)域姑曙。這是為什么我們要為每邊的 stack view定義間距約束襟交。除此之外,image view 的大小應(yīng)該固定在60X60伤靠。
現(xiàn)在選擇 stack view捣域,點(diǎn)擊布局欄里的 Pin 按鈕。分別設(shè)置上宴合,左焕梅,下,右的值為2形纺,6丘侠,1.5和0
一旦你添加了4個(gè)約束徒欣,stack view 會(huì)自動(dòng)調(diào)整大小逐样。下一步,在文件大綱里,水平拖曳 image view脂新。在彈出的菜單里挪捕,按住 shift 鍵選擇“width”和“height”選項(xiàng)。這個(gè)內(nèi)嵌視圖的大小就固定了争便。
Cool级零!你已經(jīng)完成了 prototype cell 的布局。我們繼續(xù)寫(xiě)一些代碼滞乙。
為自定義單元格創(chuàng)造一個(gè)類(lèi)
到目前為止奏纪,我們?cè)O(shè)計(jì)了單元格。但是我們?cè)鯓痈淖儤?biāo)簽的 prototype cell 值斩启?這些值應(yīng)該是動(dòng)態(tài)的序调。默認(rèn)情況下,prototype cell 應(yīng)該是和 UITableViewCell 類(lèi)相關(guān)聯(lián)的兔簇。為了更新單元格數(shù)據(jù)发绢,我們將為 prototype cell創(chuàng)建一個(gè)新的類(lèi),這個(gè)類(lèi)繼承自UITableViewCell垄琐。這個(gè)類(lèi)代表了自定義單元格的底層數(shù)據(jù)模型边酒。像往常一樣,在工程導(dǎo)航欄右擊“FoodPin”文件夾然后選擇“New File…”狸窘。
在選擇這個(gè)選項(xiàng)之后墩朦,Xcode 提示你來(lái)選擇一個(gè)模型。我們準(zhǔn)備為自定義 table view 單元格創(chuàng)建一個(gè)新的類(lèi)朦前,選擇“Cocoa Touch Class”然后點(diǎn)擊“Next”介杆。填入 RestaurantTableViewCell 作為類(lèi)名然后設(shè)置“Subclass of”的值為 UITableViewCell。
點(diǎn)擊“Next”然后把文件保存到 FoodPin 工程文件里韭寸。Xcode 應(yīng)該在工程導(dǎo)航欄里創(chuàng)建一個(gè)文件叫做 RestaurantTableViewCell.swift春哨。
下一步,在 RestaurantTableViewCell 類(lèi)里聲明下列 outlet 變量:
@IBOutlet var nameLabel: UILabel!
@IBOutlet var locationLabel: UILabel!
@IBOutlet var typelabel:UILabel!
@IBOutlet var thumnailImageView: UIImageView!
RestaurantTableViewCell 類(lèi)為自定義單位各的數(shù)據(jù)模型服務(wù)恩伺。在單元格里赴背,我們有4個(gè)屬性是可變的:
- 縮略圖圖片視圖
- 名字標(biāo)簽
- 位置標(biāo)簽
- 類(lèi)型標(biāo)簽
數(shù)據(jù)模型儲(chǔ)存和提供單元格的值來(lái)顯示。它們都是必須的晶渠,用來(lái)在界面編輯器里連接響應(yīng)的用戶(hù)界面對(duì)象凰荚。通過(guò) UI 對(duì)象來(lái)連接源代碼,我們可以改變 UI 對(duì)象的動(dòng)態(tài)值褒脯。
這是在 iOS 編程里很重要的一個(gè)概念便瑟。在 storyboard 里,你的 UI 和代碼是分開(kāi)的番川。你在界面編輯器里創(chuàng)建 UI到涂,然后在 Swift 里寫(xiě)你的代碼脊框。如果你要改變數(shù)值或者 UI 元素(如 label)的屬性,你必須給它們建立聯(lián)系践啄,這樣你代碼里的對(duì)象可以獲得一個(gè)引用到storyboard 里定義的對(duì)象浇雹。在 Swift 里,你用@IBOutlet關(guān)鍵詞來(lái)表明一個(gè)類(lèi)的屬性屿讽,那樣可以解除到界面構(gòu)建器(Interface Builder)昭灵。為了給 IBOutlet 關(guān)鍵字注釋屬性,我們叫它 outlets伐谈。
所以在上面的代碼里烂完,我們聲明了4個(gè) outlets。每個(gè) outlet都將聯(lián)系與它相關(guān)的 UI 對(duì)象诵棵。下圖描述了它們之間的關(guān)系窜护。
@IBAction vs @IBOutlet
在 HelloWorld app里我們?cè)?jīng)用@IBAction來(lái)表明動(dòng)作的方法。@IBAction和@IBOutlet之間有什么區(qū)別非春?@IBOutlet 用來(lái)表示一個(gè)屬性柱徙,這個(gè)屬性與 storyboard 里的視圖對(duì)象連接。例如奇昙,如果 outlet 與一個(gè)按鈕相連护侮,你可以用 outlet 來(lái)改變按鈕的顏色或者標(biāo)題。另一方面储耐,@IBAction 用來(lái)表明一個(gè)動(dòng)作的方法羊初,這個(gè)方法可以被確定的事件所引發(fā)。例如什湘,當(dāng)用戶(hù)點(diǎn)擊按鈕长赞,它可以引發(fā)一個(gè)動(dòng)作的方法來(lái)做一些事。
在我們建立CustomTableViewCell 類(lèi)的 outlets 和界面構(gòu)建器里的 prototype cell 之間的聯(lián)系之前闽撤,我們必須先設(shè)置 custom class得哆。
默認(rèn)情況下,prototype cell 與默認(rèn)的 UITableViewCell 類(lèi)相連哟旗。為了用 custom class 分配 prototype贩据,選擇 storyboard 里的單元格。在 Identifier inspector 里闸餐,設(shè)置 custom class 為 CustomTableViewCell饱亮。
建立聯(lián)系
接下來(lái),我們建立 outlets 和在 prototype cell 里的 UI 對(duì)象之間的聯(lián)系舍沙。在界面構(gòu)建器里近上,右擊文檔大綱視圖里的 cell 來(lái)彈出 Outlets inspector。拖曳圓環(huán)(thumdnailImageView邊上)到prototype 單元格 UIImageView 對(duì)象(看下圖)拂铡。當(dāng)你松開(kāi)按鈕時(shí)壹无,Xcode 會(huì)自動(dòng)建立聯(lián)系歼跟。
為下面的 outlets重復(fù)上面的步驟:
- locationLabel - 連接地址標(biāo)簽單元格
- nameLabel - 連接名字標(biāo)簽單元格
- typeLabel - 連接類(lèi)型標(biāo)簽單元格
在你做完所有的連接之后,UI 應(yīng)該看起來(lái)像下圖一樣格遭。
寫(xiě) table view controller 的代碼
最后,我們來(lái)到改變的最后一部分留瞳。在 RestaurantTableViewController 類(lèi)里拒迅,我們依然使用 UITableViewCell(如默認(rèn)單元格)來(lái)顯示內(nèi)容。我們需要修改一行代碼來(lái)使用自定義單元格她倘。如果你觀察 tableView(_:cellForRowAtIndexPath:)方法現(xiàn)在的執(zhí)行璧微。第二行代碼是:
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, for IndexPath: indexPath)
我已經(jīng)在之前的章節(jié)解釋過(guò) dequeueReusableCellWithIdentifier 方法的意思。它足夠靈活從隊(duì)列里返回任何單元格格式硬梁。默認(rèn)情況下前硫,它返回一個(gè) UITableViewCell 類(lèi)型的泛型單元格。為了使用 RestaurantTableViewCell 類(lèi)荧止,“轉(zhuǎn)換”dequeueReusableCellWithIdentfier 返回的對(duì)象到 RestaurantTableViewCell 是我們的責(zé)任屹电。這個(gè)轉(zhuǎn)換過(guò)程被稱(chēng)作向下類(lèi)型轉(zhuǎn)換。在 Swift 里跃巡,我們使用 as!關(guān)鍵詞來(lái)執(zhí)行強(qiáng)制轉(zhuǎn)換危号。因此,把上面的代碼行改變?yōu)椋?/p>
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! RestaurantTableViewCell
as!和as?
向下類(lèi)型轉(zhuǎn)換允許你將一個(gè)類(lèi)的值轉(zhuǎn)換到它的派生類(lèi)素邪。例如外莲,RestaurantTableViewCell是一個(gè) UITableViewCell 的子類(lèi)。dequeueReusableCellWithIdentifier 方法總是返回一個(gè) UITableViewCell 對(duì)象兔朦。如果用自定義單元格偷线,這個(gè)對(duì)象可以被轉(zhuǎn)換成特定的單元格形式(如 RestaurantTableViewCell)。Swift1.2 之前沽甥,你僅僅能夠用“as”向下類(lèi)型運(yùn)算符声邦。然而,有時(shí)對(duì)象不能轉(zhuǎn)換成制定的類(lèi)型摆舟。因此翔忽,從 Swift1.2之后,Apple 介紹了另外2個(gè)運(yùn)算符:as! 和 as?盏檐。如果你想當(dāng)確定向下類(lèi)型轉(zhuǎn)化能夠正確的執(zhí)行歇式,使用“as!”來(lái)執(zhí)行轉(zhuǎn)換。一旦你不確定一種類(lèi)型的值能轉(zhuǎn)換成另一種胡野,使用“as?”來(lái)執(zhí)行一個(gè)可選的向下類(lèi)型轉(zhuǎn)換材失。你需要執(zhí)行額外的檢查來(lái)看向下類(lèi)型轉(zhuǎn)化是否成功。
我知道你已經(jīng)等不及來(lái)測(cè)試 app 了硫豆,但是我們需要改變更多的一些代碼行龙巨。下面這些代碼行設(shè)置餐廳名字和圖片的值:
// 配置單元格...
cell.textLabl?.text = restaurantNames[indexPath.row]
cell.imageView?.image = UIImage(named: restaurantImages[indexPath.row])
textLabel 和 imageView 都是 UITableViewCell 類(lèi)的默認(rèn)屬性笼呆。因?yàn)槲覀儸F(xiàn)在使用自己的 RestaurantTableViewCell,我們需要使用自定義類(lèi)的屬性旨别。把上面的代碼行改成這樣:
//配置單元格...
cell.namelabel.text = restaurantNames[indexPath.row]
cell.thumbnailImageView.image = UIImage(named: restaurantImages[indexPath.row])
現(xiàn)在你已經(jīng)準(zhǔn)備好了诗赌。點(diǎn)擊 Run 按鈕來(lái)測(cè)試 app。你的 app 應(yīng)該看起來(lái)像下圖顯示的秸弛。試著旋轉(zhuǎn)模擬器铭若。app在橫向情況下同樣可以工作。
與前一版的 app 相比這是一個(gè)巨大的進(jìn)步递览。我們繼續(xù)把縮略圖變成圓形叼屠,讓它看起來(lái)更好。
圓形圖片
自從iOS7發(fā)布后绞铃,相比于方形圖片镜雨,iOS 更喜歡圓形圖片。你可以在內(nèi)置 app里找到圓形圖標(biāo)或者圖片儿捧,如聯(lián)系人和電話(huà)荚坞。把所有的餐廳圖片變成圓形會(huì)更好嗎?你不需要 PS 來(lái)調(diào)整圖片菲盾。你需要的僅僅是兩行代碼西剥。CALayer 類(lèi)的實(shí)例支持UIKit 里的每個(gè)視圖(如UIView,UIImageView)亿汞。設(shè)計(jì)層(layer)對(duì)象來(lái)管理支持存儲(chǔ)視圖和處理與視圖相關(guān)的動(dòng)畫(huà)瞭空。
layer 對(duì)象提供各種屬性,可以設(shè)置成控制圖像的可視化內(nèi)容例如:
- 背景色
- 邊界和邊界寬度
- 陰影顏色疗我,寬度咆畏,等等
- 不透明度
- 圓角半徑
圓角半徑是我們用來(lái)畫(huà)圓角的屬性。Xcode 提供兩個(gè)方法來(lái)編輯 layer 屬性吴裤。你可以直接通過(guò)代碼更新它的屬性旧找。這行代碼用來(lái)改變image view 的角度:
cell.thumbnailImageView.layer.cornerRadius = 30.0
cell.thumbnailImageView.clipsToBounds = true
一個(gè)更簡(jiǎn)單的方法是通過(guò)界面構(gòu)建器來(lái)改變。首先麦牺,在 stack view 里選擇 image view钮蛛。進(jìn)入 Identifier inspector,點(diǎn)擊User Defined Runtime Attributes 左下角的 Add 按鈕(+)剖膳,一個(gè)新的運(yùn)行時(shí)屬性編輯器出現(xiàn)在編輯器中魏颓。雙擊在 Key Path 文件下的新屬性來(lái)為屬性編輯新的路徑。給 layer.cornerRadius 設(shè)置新的值然后點(diǎn)擊 Return 來(lái)確定吱晒。點(diǎn)擊 Type 屬性然后選擇 Number甸饱。最后,把值設(shè)置成30.把方形的圖片變成圓形的圖片,半徑設(shè)置成圖片高度的一半叹话。這里偷遗,方形圖片的寬度是60,所以角度半徑設(shè)置成30.
當(dāng)初始化 image view 時(shí)驼壶,運(yùn)行時(shí)屬性將自動(dòng)讀取成圓角氏豌。在圓形圖片正確工作之前還有一件事你必須配置。選擇 image view 然后進(jìn)入 Attributes inspector热凹。在 Drawing 部分里泵喘,使用 Clip Subview 選項(xiàng)。這會(huì)省略?xún)?nèi)容成圓角碌嘀。
現(xiàn)在編譯運(yùn)行 app。UI 看起來(lái)更棒了對(duì)嗎歪架?沒(méi)有寫(xiě)一行代碼股冗,我們把方形圖片變成了圓形。
你可以隨意改變角度值和蚪。試著把corner radius 變成10然后看看你會(huì)得到什么止状。