Auto Layout 使用心得(五)—— 根據文字、圖片自動計算 UITableViewCell

簡介

本文中,咱們將一塊兒使用 Auto Layout 技術,讓 UITableViewCell 的高度隨其內部的 UILabel 和 UIImageView 的內容自動變化。swift

搭建界面

恢復以前刪除的按鈕

放置一個按鈕,恢復到 firstTableViewController 的鏈接:app

Image

別忘了添加約束讓他居中哦。ide

修改 firstTableViewCell

將 firstTableViewCell 的尺寸設置爲 600 * 81,將 logo 的尺寸設置爲 80 * 80。將 logo 的約束脩改成以下圖所示:性能

Image

修改 label 的尺寸和位置,添加約束以下圖:spa

Image

給 ViewController 增長 UINavigationController 嵌套

爲了便於返回。操做以下圖:prototype

Image

查看結果

Image

根據 label 自動計算 firstTableViewCell 高度

選中 label,設置 lines 行數爲 0,表示不限長度自動折行:code

Image

修改 label 的文字內容讓其超出一行:orm

import UIKit class firstTableViewController: UITableViewController {          var labelArray = Array<String>() // 用於存儲 label 文字內容     override func viewDidLoad() {         super.viewDidLoad()         var nib = UINib(nibName: "firstTableViewCell", bundle: nil)         self.tableView.registerNib(nib, forCellReuseIdentifier: "firstTableViewCell")                  // 循環生成 label 文字內容         for i in 1...10 {             var text = ""             for j in 1...i {                 text += "Auto Layout"             }             labelArray.append(text)         }     }     override func didReceiveMemoryWarning() {         super.didReceiveMemoryWarning()     }     // MARK: - Table view data source     override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {         return 50     }     override func numberOfSectionsInTableView(tableView: UITableView) -> Int {         return 1     }     override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {         return labelArray.count     }     override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {         let cell = tableView.dequeueReusableCellWithIdentifier("firstTableViewCell", forIndexPath: indexPath) as! firstTableViewCell         cell.firstLabel.text = labelArray[indexPath.row]         return cell     } }

如今到了最關鍵的時刻,驅動 UITableViewCell 適應 Label 內容:

1. 使用 estimatedHeightForRowAtIndexPath 替代 heightForRowAtIndexPath

estimatedHeightForRowAtIndexPath 是 iOS 7 推出的新 API。若是列表行數有一萬行,那麼 heightForRowAtIndexPath 就會在列表顯示以前計算一萬次,而 estimatedHeightForRowAtIndexPath 只會計算當前屏幕中顯示着的幾行,會大大提升數據量很大時候的性能。對象

2. 新建一個 prototypeCell 成員變量以複用,並在 viewDidLoad 中初始化

class firstTableViewController: UITableViewController {          var labelArray = Array<String>() // 用於存儲 label 文字內容          var prototypeCell: firstTableViewCell!     override func viewDidLoad() {         super.viewDidLoad()         var nib = UINib(nibName: "firstTableViewCell", bundle: nil)         self.tableView.registerNib(nib, forCellReuseIdentifier: "firstTableViewCell")                  // 初始化 prototypeCell 以便複用         prototypeCell = tableView.dequeueReusableCellWithIdentifier("firstTableViewCell") as! firstTableViewCell          ......

3. 計算出高度

override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {     let cell = prototypeCell     cell.firstLabel.text = labelArray[indexPath.row]     return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 }

4. 查看效果

Image

超級大坑

上面讓 firstTableViewCell 根據 label 自動計算高度的過程當中,有一個超級大坑:若是給左側 UIImageView 賦的圖片較大(大於 80px),將看到以下奇怪的結果:圖片

Image

這只是由於圖片把 UITableViewCell 撐大了,並非咱們的計算沒有效果。

解決大坑:進攻是最好的防守!根據圖片自動計算 firstTableViewCell 高度

首先,把圖片的渲染模式改爲 Aspect Fit:

Image

給 Images.xcassets 增長三張圖片,命名爲 0、一、2,尺寸從小到大:

Image

給 cellForRowAtIndexPath 增長代碼:

if indexPath.row < 3 {     cell.logoImageView.image = UIImage(named: indexPath.row.description) }

查看效果:

Image

前兩個 cell 看起來比較正常,第三個爲何多出了那麼多空白?這就是使用 Auto Layout 限制圖片寬度爲 80px 的原生問題:寬度雖然限制了,高度卻依然是原圖的高度。解決辦法也很簡單:若是圖片寬度大於 80px,就重繪一張 80px 寬度的圖片填充進去。

新建一個 Group(虛擬文件夾),叫 Extensions,並在其內部新建 UIImage.swift 文件,內容以下:

import UIKit extension UIImage {     func resizeToSize(size: CGSize) -> UIImage {         UIGraphicsBeginImageContext(size)         self.drawInRect(CGRectMake(0, 0, size.width, size.height))         let newImage = UIGraphicsGetImageFromCurrentImageContext()         UIGraphicsEndImageContext()                  return newImage     } }

給 UIImage 類擴展了一個名爲 resizeToSize 的方法,返回一個按照要求的大小重繪過的 UIImage 對象。修改 cellForRowAtIndexPath 的代碼爲:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {     let cell = tableView.dequeueReusableCellWithIdentifier("firstTableViewCell", forIndexPath: indexPath) as! firstTableViewCell     cell.firstLabel.text = labelArray[indexPath.row]          var image = UIImage(named: (indexPath.row % 3).description)!     if image.size.width > 80 {         image = image.resizeToSize(CGSizeMake(80, image.size.height * (80 / image.size.width)))     }     cell.logoImageView.image = image     return cell }

搞定!

查看效果

Image

從上圖能夠看出,cell 已經能夠根據圖片和文字中比較高的一個徹底自適應。

相關文章
相關標籤/搜索