- 一. 設(shè)置 estimatedRowHeight
一般來講計算cell的高度需根據(jù)數(shù)據(jù)模型的內(nèi)容長度,決定單元格高度,按照常規(guī)的方式,需要先給出單元格高度,代理才會執(zhí)行cellForRow函數(shù),如果height為0的話,cellForRow函數(shù)就不執(zhí)行了,而我們的計算卻發(fā)生在cellForRow函數(shù)中,計算完成后再刷新,但是這樣不可行。
正確方式: 首先設(shè)置tableView的預(yù)估高度,這樣的話,代理就會首先執(zhí)行cellForRow函數(shù),這樣就可以先計算,計算完成后保存起來,然后再執(zhí)行heightForRow函數(shù),讀取剛才保存的值。
tableView.estimatedRowHeight = 500
- 二. 設(shè)置
beginUpdates以及endUpdates函數(shù)
對于cell中有按鈕或者其他出發(fā)事件時動態(tài)修改cell高度的情況,可以在觸發(fā)事件中調(diào)用 beginUpdates 和 endUpdates 兩個函數(shù),該函數(shù)的作用區(qū)別于調(diào)用 reloadData,刷新時只會更新高度,而不會重新調(diào)用 cellForRow 函數(shù)。
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.beginUpdates()
let key = String(format: "ip:(%u,%u)", indexPath.section, indexPath.row)
allHeight[key] = 200
tableView.endUpdates()
}
example
- vc
import UIKit
class TestVC: UIViewController {
public var allHeight = [String: CGFloat]()
lazy var tableView: UITableView = {
let temp = UITableView()
temp.delegate = self
temp.dataSource = self
temp .register(TestTableViewCell.self, forCellReuseIdentifier: TestTableViewCell.description())
return temp
}()
override func viewDidLoad() {
super.viewDidLoad()
tableView.frame = view.bounds
view.addSubview(tableView)
tableView.estimatedRowHeight = 500;
tableView.reloadData()
}
}
extension TestVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
debugPrint("cellForRowAt")
guard let cell = tableView.dequeueReusableCell(withIdentifier: TestTableViewCell.description(), for: indexPath) as? TestTableViewCell else { return UITableViewCell() }
cell.content = "獲取 = \(indexPath.row)"
let key = String(format: "ip:(%u,%u)", indexPath.section, indexPath.row)
if !allHeight.keys.contains(key) {
let value = cell.dynamicHeight
allHeight[key] = value
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
debugPrint("heightForRowAt")
let key = String(format: "ip:(%u,%u)", indexPath.section, indexPath.row)
guard let height = allHeight[key] else { return 0 }
return height
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.beginUpdates()
let key = String(format: "ip:(%u,%u)", indexPath.section, indexPath.row)
allHeight[key] = 200
tableView.endUpdates()
}
}
- cell
import UIKit
class TestTableViewCell: UITableViewCell {
public var content: String? {
didSet {
dynamicHeight = 100
self.textLabel?.text = content
}
}
private (set) public var dynamicHeight: CGFloat = 0
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}