開發的過程中,經常使用UITableView的tableHeaderView視圖,對於固定高度的tableHeaderView,我們使用非常簡單。創建一個自定義視圖,計算好固定高度即可。如果要動態更新tableHeaderView的高度,僅僅是將自定義的view進行計算高度,有時候我們會發現tableHeaderView高度還是原來的高度,沒有發生變化,在是顯示的內容變多之後,會有部分內容看不到。那麼一起來看看如何處理?
實現功能:
1)自定義一個UIView,包含兩個UILabel,使用SnapKit進行佈局
2) 默認動態計算內容高度,點擊導航欄上的segmentControl進行增加和減少內容,進一步更新tableHeaderView的高度。
實現代碼:
自定義視圖部分
import UIKit
import SnapKit
class CustomHeaderView: UIView {
lazy var content: UILabel = {
let label = UILabel()
label.numberOfLines = 0
return label
}()
lazy var info: UILabel = {
let label = UILabel()
label.numberOfLines = 0
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupUI() {
backgroundColor = UIColor.gray
addSubview(content)
addSubview(info)
addConstraints()
}
func addConstraints() {
content.snp.makeConstraints { (make) in
make.left.right.top.equalToSuperview().inset(10)
}
info.snp.makeConstraints { (make) in
make.left.right.equalTo(content)
make.top.equalTo(content.snp.bottom).offset(10)
make.bottom.equalToSuperview().offset(-10)
}
}
}
上面代碼非常簡單,添加了兩個label,並添加約束,注意第二個label,bottom的約束要進行設置,相對於父視圖的位置,不然得不到正確的高度。
接下來看ViewController部分
class ViewController: UIViewController {
lazy var customView = CustomHeaderView()
lazy var tableView: UITableView = {
let table = UITableView()
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
return table
}()
@IBOutlet var segment: UISegmentedControl?
override func viewDidLoad() {
super.viewDidLoad()
addSubViews()
setCustomViewContent()
segment?.addTarget(self, action: #selector(tapSegemntControl(_:)), for: .valueChanged)
}
func addSubViews() {
view.addSubview(tableView)
tableView.snp.makeConstraints { (make) in
make.left.right.top.bottom.equalToSuperview()
}
tableView.tableHeaderView = customView
customView.snp.makeConstraints { (make) in
make.top.equalToSuperview()
make.left.right.equalTo(view) // 確定的寬度,高度由子視圖決定
}
}
func setCustomViewContent() {
customView.content.text = "患難及困苦,是磨鍊人格的最高學府;——蘇格拉底。不認識痛苦,就不是一條好漢。——雨果;永遠不要因承認錯誤而感到羞恥,因爲承認錯誤也可以解釋作你今天更聰敏。——馬羅;"
customView.info.text = "自古奇人偉士,不屈折於憂患,則不足以其學。——方孝孺;世上最可貴的是時間,世上最奢靡的是揮霍時光。——莫扎特;我要扼住命運的咽喉,它決不能使我完全屈服。——貝多芬;無論是美女的歌聲,還是鬣狗的狂吠,無論是鱷魚的眼淚,還是惡狼的嚎叫,都不會使我動搖。——恰普曼;成功=艱苦的勞動+正確的方法+少說空話。——愛因斯坦;"
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
sizeHeaderToFit()
}
func sizeHeaderToFit() {
let headerView = tableView.tableHeaderView!
headerView.setNeedsLayout()
// 立馬布局子視圖
headerView.layoutIfNeeded()
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
// 重新設置tableHeaderView
tableView.tableHeaderView = headerView
}
@objc func tapSegemntControl(_ segment: UISegmentedControl) {
if segment.selectedSegmentIndex == 0 {
customView.content.text = "永遠不要因承認錯誤而感到羞恥,因爲承認錯誤也可以解釋作你今天更聰敏。——馬羅;"
customView.info.text = "書籍並不是沒有生命的東西,它包藏着一種生命的潛力,與作者同樣地活躍。不僅如此,它還像一個寶瓶,把作者生機勃勃的智慧中最純淨的精華保存起來。——彌爾頓"
} else {
customView.content.text = " ——佚名永遠不要因承認錯誤而感到羞恥,因爲承認錯誤也可以解釋作你今天更聰敏。——馬羅;自己打敗自己是最可悲的失敗,自己戰勝自己是最可貴的勝利。 ——佚名永遠不要因承認錯誤而感到羞恥,因爲承認錯誤也可以解釋作你今天更聰敏。——馬羅;自己打敗自己是最可悲的失敗,自己戰勝自己是最可貴的勝利。 ——佚名"
customView.info.text = "書籍並不是沒有生命的東西,它包藏着一種生命的潛力,與作者同樣地活躍。不僅如此,它還像一個寶瓶,把作者生機勃勃的智慧中最純淨的精華保存起來。——彌爾頓書籍並不是沒有生命的東西,它包藏着一種生命的潛力,與作者同樣地活躍。不僅如此,它還像一個寶瓶,把作者生機勃勃的智慧中最純淨的精華保存起來。——彌爾頓書籍並不是沒有生命的東西,它包藏着一種生命的潛力,與作者同樣地活躍。不僅如此,它還像一個寶瓶,把作者生機勃勃的智慧中最純淨的精華保存起來。——彌爾頓"
}
//tableView.beginUpdates()
sizeHeaderToFit()
//tableView.endUpdates()
}
}
代碼實現分析:
2)setCustomViewContent函數是爲customView中的子視圖設置初始化內容
3)主要是在sizeHeaderToFit()函數,這裏面會對customView進行自動佈局計算其高度,並且重新賦值給tableHeaderView實現動態更新
4)tapSegemntControl函數實現內容替換,更新高度,可以看到註釋了tableView.beginUpdates()和tableView.beginUpdates(),這兩個方法可以根據高度的變化以動畫的方式進行移動
最後添加extension,實現協議
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 15
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "第\(indexPath.row)"
return cell
}
}
實現效果:
參考:
How to size a table header view using Auto Layout in Interface Builder