Swift4 - 动态计算UITableView中tableHeaderView的高度

开发的过程中,经常使用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()
    }
}

代码实现分析:


1)添加了tableView并设置了约束,然后把自定义视图(customView)设置为tableHeaderView,并设置约束,对于customView我们需要设置确定的宽度,代码中是相对于view进行添加约束,而且没有设置bottom,由子视图实现父视图的高度

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
    }
}


实现效果:


Swift4 - 动态计算UITableView中tableHeaderView的高度_第1张图片



参考:

How to size a table header view using Auto Layout in Interface Builder




你可能感兴趣的:(iOS,常用UI控件,AutoLayout)