UITableView 动态高度计算
- 一. 设置 estimatedRowHeight
一般来讲计算cell
的高度需根据数据模型的内容长度,决定单元格高度,按照常规的方式,需要先给出单元格高度,代理才会执行cellForRow
函数,如果height
为0的话,cellForRow
函数就不执行了,而我们的计算却发生在cellForRow
函数中,计算完成后再刷新,但是这样不可行。
正确方式: 首先设置tableView
的预估高度,这样的话,代理就会首先执行cellForRow
函数,这样就可以先计算,计算完成后保存起来,然后再执行heightForRow
函数,读取刚才保存的值。
tableView.estimatedRowHeight = 500
- 二. 设置
beginUpdates
以及endUpdates
函数
对于cell
中有按钮或者其他出发事件时动态修改cell
高度的情况,可以在触发事件中调用 beginUpdates
和 endUpdates
两个函数,该函数的作用区别于调用 reloadData
,刷新时只会更新高度,而不会重新调用 cellForRow
函数。
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
}
}