UITableView 教程:動態(tài) Table View Cell 高

原文地址: RAYWENDERLICH

說明:英文水平有限,主要是為了鞏固學(xué)到的知識掷贾,也能幫別人快速上手睛榄,節(jié)約時間,有任何破綻想帅,尤其是技術(shù)上的场靴,請您一定要告訴我。


學(xué)習(xí)怎樣在iOS8上使用Swift創(chuàng)建動態(tài)Cell高

旁白:其實這張圖幾乎說明了所有問題博脑,設(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 websiteMedia 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雏蛮,trailingleading 距離父視圖(也就是content view)20個點阱州。確信你沒有勾選Constrain to margins挑秉。(旁白:這個屬性就是系統(tǒng)會為你默認(rèn)兩邊留白)

圖片顯示的很清楚

確信 cell 的 title label 一直是:

  • 向上距離20個點。
  • 相對于 content view 的整體寬度苔货,左右兩邊空出20個點犀概。

現(xiàn)在鹊汛,選擇 subtitle label 設(shè)置它的 leadingtrailing阱冶,和** 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 PriorityContent Compression Resistance Priority751进苍。


在 subtitle label 上,設(shè)置 ** Horizontal** 和 ** Vertical** 的 Content Hugging PriorityContent Compression Resistance Priority750觉啊。

旁白:解釋一下拣宏,這兩個優(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 也需要 titleLabelsubtitleLabel糜烹。因此,有必要在基類里已經(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纱昧,topbottom20
  • 設(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以上的呢。)

如果你有一些問題或建議介汹,請在下面留言却嗡。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嘹承,隨后出現(xiàn)的幾起案子窗价,更是在濱河造成了極大的恐慌,老刑警劉巖叹卷,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撼港,死亡現(xiàn)場離奇詭異,居然都是意外死亡骤竹,警方通過查閱死者的電腦和手機(jī)帝牡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒙揣,“玉大人靶溜,你說我怎么就攤上這事±琳穑” “怎么了罩息?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長个扰。 經(jīng)常有香客問我瓷炮,道長,這世上最難降的妖魔是什么递宅? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任娘香,我火速辦了婚禮冬筒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茅主。我一直安慰自己舞痰,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布诀姚。 她就那樣靜靜地躺著响牛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赫段。 梳的紋絲不亂的頭發(fā)上呀打,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機(jī)與錄音糯笙,去河邊找鬼贬丛。 笑死,一個胖子當(dāng)著我的面吹牛给涕,可吹牛的內(nèi)容都是我干的豺憔。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼够庙,長吁一口氣:“原來是場噩夢啊……” “哼恭应!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耘眨,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤昼榛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后剔难,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胆屿,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年偶宫,在試婚紗的時候發(fā)現(xiàn)自己被綠了非迹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡读宙,死狀恐怖彻秆,靈堂內(nèi)的尸體忽然破棺而出楔绞,到底是詐尸還是另有隱情结闸,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布酒朵,位于F島的核電站桦锄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蔫耽。R本人自食惡果不足惜结耀,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一留夜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧图甜,春花似錦碍粥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至矿瘦,卻和暖如春枕面,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缚去。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工潮秘, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人易结。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓枕荞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搞动。 傳聞我的和親對象是個殘疾皇子买猖,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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

  • 自適應(yīng)Table View Cells 注意:這篇教程支持最新的Xcode 7.3,iOS 9和Swift 2.2...
    張嘉夫閱讀 3,012評論 9 50
  • 我認(rèn)為這是最好的建議:不斷的思考你怎樣才能把事情做得更好并且不斷的質(zhì)疑自己滋尉。-Elon Musk,Tesla Mo...
    運營老周閱讀 5,255評論 1 9
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫玉控、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,024評論 4 62
  • 沒有人會因為你的一點小破事而改變什么狮惜,你的悲傷太渺小高诺,無論放在哪里就像石沉大海。只有自己去讓自己快速成長起來碾篡,否則...
    晗凌閱讀 110評論 0 0
  • 年近四十虱而,卻越發(fā)的覺得自己年輕了起來,對比以前的照片开泽,我不禁發(fā)出感慨牡拇,誰說女人四十豆腐渣,只要你自己用心澆灌穆律,一樣...
    子林林閱讀 472評論 2 2