UITableView的tableHeaderView添加自定义子视图后与cell重叠问题
问题原因
- 你的
bottomView约束设置为topAnchor等于containerView的bottomAnchor,本质是将子视图放在了containerView的边界之外,而UIView默认clipsToBounds = false,超出父视图边界的内容不会被裁剪,自然就会盖在下方的tableViewcell上。 tableHeaderView的高度更新逻辑有误:你虽然给containerView设置了固定高度约束,但当子视图布局变化后,没有主动触发tableView更新header的实际尺寸,tableView会沿用初始设置的高度计算cell的起始位置,也会导致重叠。viewDidLoad阶段拿view.frame.size.width是不准确的,此时视图还未完成布局,宽度可能和实际屏幕宽度不符,容易出现布局偏移。- 给
containerView添加topAnchor.equalTo(tableView.topAnchor)属于多余约束,tableHeaderView的位置由tableView自行管理,额外加约束可能引发布局冲突。
修复方案
根据你的业务需求选择对应方案即可:
方案1:希望bottomView显示在containerView内部,不超出header范围
修改bottomView的约束,同时开启父视图裁剪,调整tableHeaderView更新逻辑:
class ViewController: UIViewController { private var containerView: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false view.alpha = 0.7 view.backgroundColor = .red view.clipsToBounds = true // 开启裁剪,超出部分不显示 return view }() private var bottomView: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false view.backgroundColor = .blue return view }() private(set) lazy var tableView: UITableView = { let tableView = UITableView() tableView.translatesAutoresizingMaskIntoConstraints = false tableView.dataSource = self tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") return tableView }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(tableView) containerView.addSubview(bottomView) tableView.tableHeaderView = containerView NSLayoutConstraint.activate([ tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), // 移除多余的containerView top约束,修改宽度约束为适配tableView宽度 containerView.heightAnchor.constraint(equalToConstant: 214), containerView.widthAnchor.constraint(equalTo: tableView.widthAnchor), // 修改bottomView约束,固定在containerView底部 bottomView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), bottomView.heightAnchor.constraint(equalToConstant: 114), bottomView.widthAnchor.constraint(equalTo: containerView.widthAnchor), ]) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() tableView.contentInset = UIEdgeInsets(top: -view.safeAreaInsets.top, left: 0, bottom: 0, right: 0) // 自动计算header高度,更新tableView配置 guard let headerView = tableView.tableHeaderView else { return } let targetSize = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) if headerView.frame.height != targetSize.height { headerView.frame.size.height = targetSize.height tableView.tableHeaderView = headerView } } }
方案2:希望bottomView作为header的一部分,总header高度为214+114=328
直接修改containerView的高度约束为328,其余调整逻辑和方案1一致即可,tableView会自动适配新的header高度,不会出现重叠。
内容的提问来源于stack exchange,提问作者Simon McNeil
相关产品推荐
相关产品推荐

