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


原文發表在個人我的網站:Auto Layout 使用心得(五)—— 根據文字、圖片自動計算 UITableViewCell 高度html


此係列文章代碼倉庫在 https://github.com/johnlui/AutoLayout ,有不明白的地方能夠參考個人 Auto Layout 設置哦,下載到本地打開就能夠了。ios

簡介

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

搭建界面

恢復以前刪除的按鈕

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

pic

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

修改 firstTableViewCell

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

pic

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

pic

給 ViewController 增長 UINavigationController 嵌套

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

pic

查看結果

pic

根據 label 自動計算 firstTableViewCell 高度

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

pic

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

swiftimport 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 中初始化
swiftclass 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. 計算出高度
swiftoverride 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. 查看效果

pic

超級大坑

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

pic

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

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

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

pic

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

pic

給 cellForRowAtIndexPath 增長代碼:

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

查看效果:

pic

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

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

swiftimport 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 的代碼爲:

swiftoverride func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("firstTableViewCell", forIndexPath: indexPath) as! firstTableViewCell

    cell.firstLabel.text = labelArray[indexPath.row]

    if indexPath.row < 3 {
        var image = UIImage(named: indexPath.row.description)!
        if image.size.width > 80 {
            image = image.resizeToSize(CGSizeMake(80, image.size.height * (80 / image.size.width)))
        }
        cell.logoImageView.image = image
    }

    return cell
}

搞定!

查看效果

pic

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

致謝

感謝 《動態計算UITableViewCell高度詳解》,給我提供了許多基礎知識和靈感。

下一步:Auto Layout 使用心得(六)—— 製造炫酷的下拉刷新動畫

相關文章
相關標籤/搜索