原文地址: RAYWENDERLICH
說明:英文水平有限,主要是為了鞏固學(xué)到的知識掷贾,也能幫別人快速上手睛榄,節(jié)約時間,有任何破綻想帅,尤其是技術(shù)上的场靴,請您一定要告訴我。
(旁白:其實這張圖幾乎說明了所有問題博脑,設(shè)置好
constraints
憎乙,其它都不是問題。補充一下:這篇教程實際上就是 auto layout教程叉趣。)
你應(yīng)該在使用 table view cells 的時候經(jīng)常會寫很多代碼泞边,來手動計算label,image view疗杉,text field 和 cell 相關(guān)的每一個控件的高阵谚。
坦白講,這種方法很容易出錯且容易讓人迷糊看不懂烟具。
在這篇教程里梢什,你將學(xué)會怎樣創(chuàng)建自定義 cell 并且根據(jù)內(nèi)容動態(tài)調(diào)整 cell 的高度,你可能會想朝聋,"這得需要多少工作量...!"
Nope! * (旁白:you are right ~*)
你很幸運嗡午,Apple 可以讓你在 iOS8 里很容易的做到這些。你將從寫適配代碼中解脫出來冀痕。但是還是要實現(xiàn) table view 的數(shù)據(jù)源和代理方法荔睹。
讓我們開始
iOS6出來幾天之后,Apple 介紹了一個超贊的技術(shù):auto layout言蛇。程序猿們開始慶祝僻他,街頭聚會,寫贊歌...(旁白:要不要這么夸張啊)
好吧腊尚,也許有些問題吨拗,但它畢竟是一次大飛躍(旁白:是這個意思吧,哈哈)
在給了很多開發(fā)者希望的同時,auto layout 還是很難用的劝篷。尤其是手寫 auto layout 代碼哨鸭。Interface Builder 在設(shè)置 constraints 時也并不理想。
很快到現(xiàn)在携龟,伴隨著對 Interface Builder 的所有改進(jìn)和 iOS8 的到來兔跌,我們現(xiàn)在可以很容易的動態(tài)設(shè)置 table view cells 的高度了。
你需要不得不做的事情有:
1峡蟋,在創(chuàng)建 table view cells 時使用 auto layout坟桅。
2,設(shè)置 table view 的** rowHeight 等于 UITableViewAutomaticDimension 蕊蝗。
3仅乓,設(shè)置 estimatedRowHeight ** 的值或者實現(xiàn)預(yù)估高度的代理方法。
這是你需要知道的幾個要點蓬戚,現(xiàn)在開始下載代碼夸楣,搞起項目了。
(旁白:確實很重要子漩,雖然說了不少廢話豫喧,但是并不是浪費時間的。)
教程 App 概覽
設(shè)想一下你的老大來到你面前幢泼,對你說:“我們的用戶在為看** Deviant Artists 的方法而大聲抗議”紧显。
我會問:"什么是 Deviant Artists "。
你的頭解釋說:“那是一個藝術(shù)家們用來分享自己作品的社交平臺缕棵。你可以通過 Deviant Art website 和 Media RSS endpoint 來了解藝術(shù)家的公告和動態(tài)孵班。”
老大:“我們開始做這個 App 吧招驴,但是要怎么樣把內(nèi)容顯示到表格上呢篙程?你能做到吧?”
你突然受到了感召别厘,走進(jìn)最近的電話亭虱饿,換上了披風(fēng)成了super Dev..
但你不需要弄騙人的把戲做你老大的英雄,用你的編程技術(shù)就可以做到了触趴。
(旁白:你怎么不去做導(dǎo)演啊...)
首先氮发,現(xiàn)在客戶端代碼(項目的起始程序)這里。
(旁白:語法有一些過時雕蔽,打開項目會自動讓你轉(zhuǎn)換到最新的語法折柠,轉(zhuǎn)換完之后會報一個錯宾娜,將 ** FeedViewController.swift 里的 deselectAllRows **方法替換成如下代碼:
func deselectAllRows() {
if let selectedRows = tableView.indexPathsForSelectedRows{
for indexPath in selectedRows {
tableView.deselectRowAtIndexPath(indexPath, animated: false)
}
}
}
)
這個項目使用的** CocoaPods 批狐,因此打開 DeviantArtBrowser.xcworkspace ** (不是** xcodeproj 這個文件),pods 已經(jīng)包含到 zip 包里了,所以不用在重新 pod install **嚣艇。
注意:如果你不清楚什么是 CocoaPods 承冰,可以看下這個教程。
打開** Main.storyboard (在 DeviantArtBrowser ** project 下的** DeviantArtBrowser 文件夾 Views **分組里)食零,你將會看到下面四個場景:
從左到右困乒,它們是:
- 頂級的導(dǎo)航控制器。
- **FeedViewController **,標(biāo)題是 ** Deviant Browser **贰谣。
- 還有兩個都是** DetailViewController 的場景娜搂,標(biāo)題分別是Deviant Article** 和 Deviant Media ,一個只用來顯示文本吱抚,另一個文本和圖片一起顯示百宇。
編譯并運行,你將看到一些控制臺上的輸出日志和一個短暫出現(xiàn)的活動指示器秘豹,但是在 app 里并沒有什么內(nèi)容顯示出來携御。
日志輸出像下面一樣:
2014-11-08 14:30:02.746 DeviantArtBrowser[70847:829282] GET 'http://backend.deviantart.com/rss.xml?q=boost%3Apopular'
2014-11-08 14:30:03.297 DeviantArtBrowser[70847:829282] 200 'http://backend.deviantart.com/rss.xml?q=boost%3Apopular' [0.5506 s]
app 發(fā)起一個網(wǎng)絡(luò)請求并獲得返回,但是并沒有做任何事既绕。
(旁白:如果請求失敗啄刹,很可能是iOS9系統(tǒng)下不可用http協(xié)議,打開info.plist的源碼凄贩,粘貼如下內(nèi)容誓军。)
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
現(xiàn)在,打開** FeedViewController.swift(在 Controllers **文件夾的下面)怎炊。
看下 ** parseForQuery **這段代碼:
func parseForQuery(query: String?) {
showProgressHUD()
parser.parseRSSFeed(deviantArtBaseUrlString,
parameters: parametersForQuery(query),
success: {(let channel: RSSChannel!) -> Void in
self.convertItemPropertiesToPlainText(channel.items as! [RSSItem])
self.items = (channel.items as! [RSSItem])
self.hideProgressHUD()
self.reloadTableViewContent()
}, failure: {(let error:NSError!) -> Void in
self.hideProgressHUD()
println("Error: \(error)")
})
}
** parser 是一個 RSSParser 的實例谭企,屬于 MediaRSSParser 的一部分。
這是一個得到 Deviant Art ** RSS feed 的網(wǎng)絡(luò)請求评肆,它會在成功的 block 里返回一個** RSSChannel 實例债查。然后解析數(shù)據(jù)將 HTML 轉(zhuǎn)成普通文本, channel.items 和控制器里的 items **屬性都是數(shù)組瓜挽。
** channel.items 數(shù)組包含 RSSItem **對象盹廷,每一個對象元素都是一個 RSS feed。(現(xiàn)在你該知道要將什么顯示到表格里了吧久橙,正是 ** items **數(shù)組!)
最后俄占,項目里會有一些** //TODO:Write this... **的注釋,是為了告訴我們需要實現(xiàn)些什么淆衷。
開始創(chuàng)建自定義 Cell
查看源代碼之后缸榄,你現(xiàn)在知道這個 app 有了不錯的數(shù)據(jù),但是什么都沒有顯示出來祝拯,要顯示它們甚带,你需要創(chuàng)建一個自定義的 table view cell她肯。
- 添加一個新類到** DeviantArtBrowser**項目里。
- 名字是 ** BasicCell 并且繼承自 UITableViewCell **鹰贵。
- 確信** Also create xib file **沒有被勾選晴氨。
- 語言選擇** Swift 。
打開 BasicCell.swift ** 并添加如下屬性:
@IBOutlet var titleLabel: UILabel!
@IBOutlet var subtitleLabel: UILabel!
接下來碉输,打開** Main.storyboard 籽前,拖拽一個UITableViewCell到** FeedViewController 的 table view上。
設(shè)置 BasicCell 的 Custom Class 敷钾。
設(shè)置 BasicCell 的 Identifier (Reuse Identifier) 枝哄。
設(shè)置 cell 的 Row Height 為 83 。
拖拽一個 UILabel 到 cell 上阻荒,設(shè)置 text為 Title 膘格。
設(shè)置 label 的 Lines 為 0,就是沒有上限财松。(行數(shù)可以設(shè)置很多)
接下來像下面截圖一樣設(shè)置 label 的尺寸和位置瘪贱。
連接 cell 的 label 到 BasicCell 的 titleLabel ** outlet 上。
接下來辆毡,拖拽第二個 UILabel 到 cell 上菜秦,像第一個 label 一樣,并且設(shè)置 text 為** Subtitle 舶掖。
像第一個 label 一樣球昨,按照下面的截圖來設(shè)置 Subtitle 的尺寸和位置。
設(shè)置 subtitle label 的 Color ** 為 * Light Gray Color 眨攘;字體大小為 * 15.0 主慰;并且 Lines **為 0 ;
將 cell 的 subtitle label 連接到 BasicCell 上的 subtitleLabel outlet上鲫售。
接下來共螺,你將給** BasicCell **添加 auto layout ** constraints ** ,來布局 cell 情竹。
注意:如果你對 auto layout 還不太熟悉藐不,不清楚怎么設(shè)置 auto layout constraints ,可以看下 這個教程秦效。
選擇 title label 且設(shè)置它的 top雏蛮,trailing,leading 距離父視圖(也就是content view)20個點阱州。確信你沒有勾選Constrain to margins挑秉。(旁白:這個屬性就是系統(tǒng)會為你默認(rèn)兩邊留白)
確信 cell 的 title label 一直是:
- 向上距離20個點。
- 相對于 content view 的整體寬度苔货,左右兩邊空出20個點犀概。
現(xiàn)在鹊汛,選擇 subtitle label 設(shè)置它的 leading,trailing阱冶,和** bottom 距離父視圖20個點。再次確認(rèn)滥嘴,沒有勾選Constrain to margins木蹬。
像 title label 一樣,確定在 subtitle label 上的 constraints 若皱,是按照底部距離 content view 20個點镊叁,左右距離 content view 也是20個點。
(旁白:還是看圖更直觀一些)
技巧: 使用 auto layout 布局 UITableViewCell 時走触,要確定這些約束都布局到了每一個 subview 的四邊晦譬,也就是說,每一個 subview 都應(yīng)該有 leading互广,top敛腌,trailing 和 bottom 約束。
除此之外惫皱,** contentView 的頂部到底部都要有清晰的約束條件像樊, 你要能確定,這些子視圖的約束可以正確的指定出 contentView **的高度旅敷。
另一部分技巧是生棍,interface Builder 經(jīng)常在你缺失一些約束的情況下,沒有警告提示媳谁。在運行項目時涂滴,auto layout 沒有返回正確的高度,比如會返回 0 的高度晴音,遇到這些問題需要你重新調(diào)整約束條件 直到滿足條件為止柔纵。
現(xiàn)在, 選擇 subtitle label, 按住 Control 并拖拽到 title label锤躁。選擇 Vertical Spacing 連接** subtitle label 的頂部和 title label **的底部首量。
在 title label 上,設(shè)置 ** Horizontal** 和 ** Vertical** 的 Content Hugging Priority 和 Content Compression Resistance Priority為 751进苍。
在 subtitle label 上,設(shè)置 ** Horizontal** 和 ** Vertical** 的 Content Hugging Priority 和 Content Compression Resistance Priority為 750觉啊。
(旁白:解釋一下拣宏,這兩個優(yōu)先級的意思,**Content Hugging Priority **就是級別越高杠人,越不會被拉開勋乾,抻開宋下。 **Content Compression Resistance Priority **就是級別越高,越不會被壓縮辑莫,擠掉学歧。這個還是要看具體的例子來理解的,有一點繞各吨。)
這就是告訴 auto layout 怎樣去適配 labels 的文本-區(qū)分 title label 和 subtitle label 之間約束的優(yōu)先級枝笨。在這個例子里,這些約束基本滿足了條件揭蜒。
檢查: 上面的約束條件滿足情況了嗎横浑?
1,每一個子視圖的所有側(cè)邊都有約束嗎屉更?Yes徙融。
2,**contentView 從上到下都有約束嗎瑰谜?Yes(旁白:只有這樣 contentView 才能確定出自己的高度欺冀,像 UIScrollView 一樣,才能知道自己的 contentSize萨脑,否則運行起來都不能滑動脚猾。)
**titleLabel **距頂部有20個點,它和 **subtitleLabel **之間的距離是4個點砚哗,并且 ** subtitleLabel **和底部有19.5個點龙助。
所以,現(xiàn)在 auto layout 已經(jīng)可以動態(tài)設(shè)置 cell 的高度了蛛芥。
接下來提鸟,你要創(chuàng)建一個 ** BasiceCell ** 跳轉(zhuǎn)到 **Deviant Article **場景的鏈接(segue)。
選擇你的 BasiceCell仅淑,按住 control 拖拽到 **Deviant Article 場景,從 Selection Segue **選項中選擇 **Push **称勋。
Interface Builder 將自動更改 Accessory 屬性為 Disclosure Indicator,這是為了指示你從 cell 導(dǎo)航到詳情里去涯竟。然而赡鲜,這并不符合程序的設(shè)計,選擇 **BasiceCell ** ,更改 ** Accessory **為 None庐船。
現(xiàn)在银酬,用戶在任何時候點擊 BasicCell 都會跳轉(zhuǎn)到 **DetailViewController **里了。
哇塞筐钟,你的** BasicCell 已經(jīng)設(shè)置完了揩瞪!如果你編譯運行 app 的話,還是毛都看不到篓冲,為啥呢...(旁白:自言自語..)
還記得哪些** TODO **的注釋嗎李破?宠哄,對了,這就是問題所在了嗤攻。你需要到哪些 TODOs 里寫一些代碼毛嫉。
配置 Table View
首先,你需要配置下這個 table view妇菱。
打開** FeedViewController.swift ** 承粤,用下面的代碼替換**configureTableView() **這個方法。
func configureTableView() {
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160.0
}
確信 table view 是用 auto layout 來動態(tài)設(shè)置高的時候恶耽,將 **rowHeight 設(shè)置為 UITableViewAutomaticDimension 。
確定這些之后颜启,你還要提供一個 ** estimatedRowHeight 的值偷俭。小意思,160.0是一個隨意的值也可以使用缰盏。在你的項目里涌萤,你可能也想根據(jù)數(shù)據(jù)類型設(shè)置一個更好的值。
實現(xiàn) UITableView 的 Data Source
接下來口猜,你需要實現(xiàn)** UITableViewDataSource 的協(xié)議方法负溪。
首先,在 FeedViewController **里加上這個常量:
let basicCellIdentifier = "BasicCell"
這可以讓你用這個標(biāo)識在 storyboard 里取得 ** BasicCell 济炎。
接下來川抡,用 tableView(_:numberOfRowsInSection:) **返回從 Deviant Art 獲取到數(shù)據(jù)個數(shù):
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
然后用,下面的代碼替換** tableView(_:cellForRowAtIndexPath:) **這個方法须尚。
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return basicCellAtIndexPath(indexPath)
}
func basicCellAtIndexPath(indexPath:NSIndexPath) -> BasicCell {
let cell = tableView.dequeueReusableCellWithIdentifier(basicCellIdentifier) as! BasicCell
setTitleForCell(cell, indexPath: indexPath)
setSubtitleForCell(cell, indexPath: indexPath)
return cell
}
func setTitleForCell(cell:BasicCell, indexPath:NSIndexPath) {
let item = items[indexPath.row] as RSSItem
cell.titleLabel.text = item.title ?? "[No Title]"
}
func setSubtitleForCell(cell:BasicCell, indexPath:NSIndexPath) {
let item = items[indexPath.row] as RSSItem
var subtitle: NSString? = item.mediaText ?? item.mediaDescription
if let subtitle = subtitle {
// Some subtitles are really long, so only display the first 200 characters
if subtitle.length > 200 {
cell.subtitleLabel.text = "\(subtitle.substringToIndex(200))..."
} else {
cell.subtitleLabel.text = subtitle as String
}
} else {
cell.subtitleLabel.text = ""
}
}
這邊發(fā)生什么:
- 在 tableView(:cellForRowAtIndexPath:) 里崖堤,調(diào)用basicCellAtIndexPath(:) 方法獲取一個** BasicCell **。
- 在basicCellAtIndexPath(:)里獲取一個** BasicCell **耐床,使用setTitleForCell(:indexPath:) 方法設(shè)置 title label 的text密幔,使用** setSubtitleForCell(_:indexPath:) **方法設(shè)置 subtitle label 的text,然后return 這個 cell撩轰。
現(xiàn)在胯甩,你需要實現(xiàn)... 等等,搞定了堪嫂!就這么簡單偎箫?
編譯運行簇捍,你將看到這個表格:
圖片在哪呢愚争?
這個app看起來還不錯格了,但是好像感覺缺了點什么易遣?
噢沫屡,藝術(shù)在哪呢?
Deviant Art 上都是圖片躏鱼,但這個 app 沒有顯示它們戒良,你需要去修復(fù)下這個問題,不然塔插,你的老大會讓你失去理智梗摇!
有個方法是在你的** BasicCell **上加一個 image view。
但是在 Deviant Art 上帶圖片的信息和純文字的信息都有想许,所以更好的做法是新建一個自定義 cell伶授。
增加一個繼承自** BasicCell **的新類到項目里,名字叫 ImageCell流纹,原因是你的新 cell 也需要 titleLabel 和 subtitleLabel糜烹。因此,有必要在基類里已經(jīng)存在一些方法的時候再做所有的事嗎漱凝?
打開** ImageCell.swift ** 并且增加下面的屬性:
@IBOutlet var customImageView: UIImageView!
這個屬性的名字是** customImageView疮蹦,因為在 UITableViewCell 里已經(jīng)有了一個叫 ImageView **的屬性了。
打開** Main.storyboard 茸炒,選擇 basic cell 使用 ?C 愕乎,或者從菜單里選擇 Edit > Copy **。
選擇這個 table view 并且 按下 **?V 壁公,或者 Edit > Paste **感论,去創(chuàng)建一個 cell 的新 copy 。
注意:如果你操作有誤紊册,沒有得到想要的結(jié)果比肄,記得使用** ?Z 或者 Edit > Undo **來撤銷操作。
選擇新 cell 囊陡,更改它的Custom Class為** ImageCell **薪前。同樣的,更改它的 Reuse Identifier ** 為 ImageCell **关斜。
在** ImageCell 上選擇 title label示括,更改它的位置 x 為128**,且寬度為 172痢畜。subtitle label 也是一樣垛膝。
Interface Builder 將會有一些警告,因為這些 labels 擺放的位置和約束設(shè)置的不一樣丁稀。
正確的做法是吼拥,選擇** ImageCell 上的 title label 刪掉 leading 這條約束,subtitle label 也是一樣刪掉 leading **約束线衫。
現(xiàn)在選擇** ImageCell 的 title label凿可,按照下面的截圖改變它的 Intrinsic Size 的 Placeholder 的值。同樣的,改變 subtitle label 的 Intrinsic Size 枯跑。
(這是用來告訴 Interface Builder 去更新當(dāng)前 view 的 frame 的占位符惨驶,Interface Builder 將不會顯示警告了。)
你需要在 cell 上增加一個 image view敛助。但是現(xiàn)在的高度有一點小粗卜,所以選擇 ImageCell 修改它的 Row Height 為 141**。
現(xiàn)在纳击,拖拽一個 image view 到** ImageCell **上续扔,按照下面的截圖設(shè)置這個新 view 的位置和尺寸。
接下來焕数,選擇這個 image view 做如下布局:
- 設(shè)置 leading纱昧,top 和 bottom 為20。
- 設(shè)置** width 和 height 為 100**堡赔。
- 確認(rèn) **Constrain to margins **沒有被勾選
-
最后點擊** Add 5 constrain **的按鈕识脆。
選擇** image view ** 顯示它的所有約束,然后選擇它的 bottom 約束來編輯它加匈。在屬性編輯器里存璃,改變** Relation 為 Greater Than or Equal 它的 Priority 為 999仑荐。
同樣的雕拼,選擇 subtitle label 去顯示它的所有約束條件,然后選擇它的 bottom 粘招,在屬性編輯器里啥寇,改變 Relation 為 Greater Than or Equal 它的 Priority**為 1000。
這是告訴 auto layout 在** imageView 和 subtitleLabel 向下的約束都為20個點的時候洒扎,打破 imageView 的辑甜,遵循 subtitleLabel 的。(旁白:因為它的優(yōu)先級高袍冷,這樣避免約束沖突磷醋。)
然后將 image view 的** height 和 width 約束的優(yōu)先級 Priority 設(shè)置成 999 。
這是因為自定義的約束有時候會和系統(tǒng)定義的約束之間會產(chǎn)生沖突胡诗,這時就是告訴 auto layout 邓线,“如果一定要這么做,就打破這些自定義的約束吧”
(旁白:系統(tǒng)定義的優(yōu)先級高煌恢,1000骇陈。)
在大部分情況下,auto layout 都會滿足這些約束瑰抵。在極少數(shù)的情況下它會打破這些約束你雌,比如在改變設(shè)備方向時,但通常都是1-2的像素偏差二汛,不明顯婿崭。
提示: 尤其在 table view cell上拨拓, auto layout 不總是很明顯的提示這些約束。
如果你在控制臺上看到這些 auto layout 不得不打破一個約束的警告信息逛球,你就要試著去調(diào)整下你的約束條件的** priorities **了千元。
最后,選擇 ImageCell上的 title label 使用 Pin Button 來設(shè)置下 leading 約束為 8颤绕。subtitle label 也是一樣的幸海。
現(xiàn)在你的** ImageCell **上的約束看起來是這個樣子的:
你需要選擇** ImageCell 和 image view 的 customImageView ** outlet 進(jìn)行鏈接。
你需要一個** ImageCell 跳轉(zhuǎn)到 Deviant Media 場景的鏈接(segue)奥务,
這樣用戶點擊 ImageCell **就可以看到詳情了物独。
像之前設(shè)置 basic cell 一樣, 選擇** ImageCell 氯葬,按住 control 并拖拽到 Deviant Media 場景挡篓,然后在 Selection Segue 選項中選擇 Push **。
確認(rèn)你的** Accessory 改回為 None **帚称。
非常好官研,你的** ImageCell **已經(jīng)設(shè)置完成了!現(xiàn)在你可以加一些代碼讓它顯示出來了闯睹。
顯示這些圖片戏羽!
打開** FeedViewController.swift ** 在上面增加一個常量:
let imageCellIdentifier = "ImageCell"
接下來替換** tableView(_:cellForRowAtIndexPath:) **的代碼:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if hasImageAtIndexPath(indexPath) {
return imageCellAtIndexPath(indexPath)
} else {
return basicCellAtIndexPath(indexPath)
}
}
func hasImageAtIndexPath(indexPath:NSIndexPath) -> Bool {
let item = items[indexPath.row]
let mediaThumbnailArray = item.mediaThumbnails as! [RSSMediaThumbnail]
for mediaThumbnail in mediaThumbnailArray {
if mediaThumbnail.url != nil {
return true
}
}
return false
}
func imageCellAtIndexPath(indexPath:NSIndexPath) -> ImageCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier(imageCellIdentifier) as! ImageCell
setImageForCell(cell, indexPath: indexPath)
setTitleForCell(cell, indexPath: indexPath)
setSubtitleForCell(cell, indexPath: indexPath)
return cell
}
func setImageForCell(cell:ImageCell, indexPath:NSIndexPath) {
let item: RSSItem = items[indexPath.row]
// mediaThumbnails are generally ordered by size,
// so get the second mediaThumbnail, which is a
// "medium" sized image
var mediaThumbnail: RSSMediaThumbnail?
if item.mediaThumbnails.count >= 2 {
mediaThumbnail = item.mediaThumbnails[1] as? RSSMediaThumbnail
} else {
mediaThumbnail = (item.mediaThumbnails as NSArray).firstObject as? RSSMediaThumbnail
}
cell.customImageView.image = nil
if let url = mediaThumbnail?.url {
cell.customImageView.setImageWithURL(url)
}
}
像上面創(chuàng)建** BasicCell **一樣,但是有一點不同楼吃,有一些新的代碼:
- hasImageAtIndexPath(_:) 檢查IndexPath下的item的** mediaThumbnail的 url 不為空始花。如果不為空的要使用 ImageCell **來展示數(shù)據(jù)。
- **imageCellAtIndexPath(:) 和 basicCellAtIndexPath(:) 一樣孩锡,但是它要用 setImageForCell(_:indexPath:) **來設(shè)置下圖片酷宵。
- ** setImageForCell(:indexPath:) ** 嘗試獲取第二個 media thumbnail。使用 AFNetworking提供的** setImageWithURL(:) **方法來獲取圖片躬窜。
編譯運行浇垦,你將看到漂亮的藝術(shù)圖片!默認(rèn)荣挨,app 檢索 “popular“ 分類的數(shù)據(jù)男韧,但你也能按照藝術(shù)家搜索。
試著輸入** by:CheshireCatAr t** 并搜索垦沉。這是我的一個朋友煌抒,Devin Kraft,他是一個杰出的畫家。(查看他的website)厕倍。
這是我很喜歡的一位寡壮,他在 Deviant Art 上很活躍,發(fā)過作品和博客。因此况既,他的賬號是個很好的測試賬號这溅,可以測試帶圖片的 cell 和不帶圖片的 cell。
這個 app 已經(jīng)看起來很漂亮了棒仍,但是你還可以讓你的老大對你的技能信心提升一到兩個級別悲靴。
優(yōu)化表格
還記得很早之前設(shè)置** estimatedRowHeight 為 160.0 的時候嗎?這個屬性是在 BasicCell **的豎屏方向上工作的莫其。但是這個值非常的不準(zhǔn)癞尚。
你可以使用** UITableViewDelegate **提供的,在運行時給 cell 估算高度的方法替換這個值乱陡。
改之前浇揩,你需要刪除** configureTableView(): **里的一行代碼:
tableView.estimatedRowHeight = 160.0
現(xiàn)在,在** // MARK: UITextFieldDelegate **組下增加下面的方法憨颠。(實際上胳徽,你可以在這個類的任何地方增加它們,但這樣結(jié)構(gòu)比較清楚易讀爽彤。)
// MARK: UITableViewDelegate
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if isLandscapeOrientation() {
return hasImageAtIndexPath(indexPath) ? 140.0 : 120.0
} else {
return hasImageAtIndexPath(indexPath) ? 235.0 : 155.0
}
}
func isLandscapeOrientation() -> Bool {
return UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation)
}
這個預(yù)估 cell 高的方法很簡單养盗。檢查當(dāng)前方向是否是橫屏并且如果當(dāng)前 index path 有圖片的話,返回一個預(yù)先裁定的值适篙。
提示:不論你是實現(xiàn)的代理方法往核,還是簡單的設(shè)置了一個** estimatedRowHeight 固定的值。
這個 table view 會在代理方法和 estimatedRowHeight 的值之中選擇一個匙瘪。它會影響到滑動的指示條和滑動的性能铆铆。(是否卡頓)
如果你的 cell 預(yù)估的高度不太正確蝶缀,那么在滑動的時候就會卡頓丹喻,滑動指示條不太準(zhǔn),內(nèi)容也會混亂翁都。
如果你的預(yù)估是準(zhǔn)確的碍论,計算就會慢,table view 滾動也會變慢柄慰。
這個成功的關(guān)鍵就在于在準(zhǔn)確和不準(zhǔn)確之間找一個平衡鳍悠,減少不必要的計算成本。
(旁白:難道自己慢慢調(diào)試這個數(shù)值嗎坐搔?)
你還是使用固定的值來估算的高度藏研,但是現(xiàn)在可以根據(jù) cell 的類型和設(shè)備的方向來設(shè)置更合理的高度了。你可以設(shè)置自己感興趣的值概行,但是記住訣竅就是能讓它計算的更快就行蠢挡。
編譯并運行,你應(yīng)該能看到 table view 滑動的很流暢,看起來很棒业踏。
這就是方法的最后實現(xiàn)禽炬,這個 app 現(xiàn)在完成了!
從這去哪呢
你可以去下載完成項目勤家,在這
(旁白:上面的路徑下載下來的項目編譯會報錯腹尖,因為它是用Xcode6.3和Swift1.2做的,轉(zhuǎn)換到最新語法之后伐脖,在像上面已經(jīng)提到過的修改一個方法的代碼热幔,添加http白名單。你也可以下載這里已經(jīng)修改過的代碼)
Table views 可能是iOS里面組織數(shù)據(jù)視圖中最常用的了讼庇。你的 apps 會很復(fù)雜断凶,你可能要使用各種類型的自定義 cell 來布局。幸運的是 iOS8 和 auto layout 能很容易的做到這些巫俺。
(旁白:不幸的是认烁,有多少 app 是只支持iOS8以上的呢。)
如果你有一些問題或建議介汹,請在下面留言却嗡。