前言
UITableView
的有一个tableHeaderView属性:整体列表的头部,滚动的时候回跟随列表整体一起滚动。
常规设置tableHeaderView会给定一个UIView再去设定frame,一旦是动态布局还得计算个别动态控件的高度,再将tableHeaderView的height更新,及其麻烦。
因此用动态布局设定headerView不香么?
动态布局设定tableHeaderView
先来看看效果
上边这个效果就是拿定义的View嵌入到tableView的tableHeaderView中做到的。
完整代码:
import UIKit
import SnapKit
class ViewController: UIViewController{
let headerView = TestHeaderView(frame: .zero)
let tableView : UITableView = UITableView(frame: .zero, style: .plain)
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.separatorStyle = .none //隐藏tableview分割线
//把 autoresizingMask 转换为 Constraints,我们要用自动因此设置为false,不加会警告
tableView.snp.makeConstraints { (make) in
make.edges.equalToSuperview().offset(0)
}
tableView.tableHeaderView = headerView//相当于 addsubview
headerView.backgroundColor = .lightGray
headerView.updateBlock = {[weak self] in
self?.headerView.layoutIfNeeded()
self?.tableView.tableHeaderView?.layoutIfNeeded()
}
headerView.snp.makeConstraints { (make) in
make.left.top.equalToSuperview()
make.width.equalTo(UIScreen.main.bounds.width)//
//height 动态嵌入 不用获取
}
headerView.loadData()
}
}
extension TestHeaderView {
func loadData() {
header.backgroundColor = .red
content.numberOfLines = 0
content.text = "是打算打算打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打大家快来萨达所打所多所打算大萨达撒大家快来萨达所打大家快所打大家快"
title.text = "撒大声地计算的撒大声地"
if let tmpUpdateBlock = self.updateBlock {
tmpUpdateBlock()
}
}
}
class TestHeaderView: UIView {
private let header = UIImageView()
private let title = UILabel()
private let content = UILabel()
private let bottomLine = UIView()
typealias UpdateHeightBlock = ()->();
var updateBlock:UpdateHeightBlock?
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupUI() {
self.addSubview(header)
self.addSubview(title)
self.addSubview(content)
self.addSubview(bottomLine)
title.backgroundColor = .green
content.backgroundColor = .red
header.layer.cornerRadius = 14
header.layer.masksToBounds = true
header.isUserInteractionEnabled = true
// header.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(headerClick)))
bottomLine.backgroundColor = .darkGray
header.snp.makeConstraints { (make) in
make.left.top.equalTo(15)
make.size.equalTo(28)
}
title.snp.makeConstraints { (make) in
make.centerY.equalTo(header.snp.centerY)
make.left.equalTo(header.snp.right).offset(5)
make.right.equalTo(-15)
}
content.snp.makeConstraints { (make) in
make.top.equalTo(header.snp.bottom)
make.left.equalTo(title)
make.right.equalTo(title)
}
bottomLine.snp.makeConstraints { (make) in
make.left.equalTo(15)
make.right.equalTo(title)
make.top.equalTo(content.snp.bottom).offset(10)
make.height.equalTo(5)
make.bottom.equalToSuperview()
}
}
}
非常简单的实现代码核心就是在TestHeader类中声明一个闭包,当loadData
布局后,通过controller层将headerView和tableView 使用layoutIfNeeded()
更新布局即可。
核心代码:
headerView.updateBlock = {[weak self] in
self?.headerView.layoutIfNeeded()
self?.tableView.tableHeaderView?.layoutIfNeeded()
}
如果我们在工期紧的时候需要做这种动态布局的复杂页面
,可以将tableView的tableHeader作为我们的视图容器,contentSize,约束,tableview内部会全部计算好。肯定是比scrollView省劲的。