点击按钮后无法更新TableViewHeader及内部UILabel高度的问题
问题:设置长状态文本后,Label和TableViewHeader高度未更新
点击按钮设置新的长状态文本时,profileStatusLabel的高度以及TableViewHeader的高度均未发生变化。

ProfileHeaderView: UIView
import UIKit ... private lazy var profileStatusLabel: UILabel = { let profileStatusLabel = UILabel() profileStatusLabel.numberOfLines = 0 profileStatusLabel.text = "Looking for a big, young, good looking, able to cook female gorilla" profileStatusLabel.textColor = .gray profileStatusLabel.font = profileNameLabel.font.withSize(14) profileStatusLabel.textAlignment = .left profileStatusLabel.sizeToFit() profileStatusLabel.translatesAutoresizingMaskIntoConstraints = false return profileStatusLabel }() private lazy var setStatusButton: UIButton = { let setStatusButton = UIButton() setStatusButton.backgroundColor = .systemBlue setStatusButton.layer.cornerRadius = 4 setStatusButton.layer.shadowOffset = CGSize(width: 4, height: 4) setStatusButton.layer.shadowOpacity = 0.7 setStatusButton.layer.shadowRadius = 4 setStatusButton.layer.shadowColor = UIColor.black.cgColor setStatusButton.setTitle("Set status", for: .normal) setStatusButton.setTitleColor(.white, for: .normal) setStatusButton.titleLabel?.font = setStatusButton.titleLabel?.font.withSize(14) setStatusButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside) setStatusButton.translatesAutoresizingMaskIntoConstraints = false return setStatusButton }() private lazy var statusText: String = { return statusText }() private func setupView() { addSubview(profileImageView) addSubview(profileNameLabel) addSubview(profileStatusLabel) addSubview(statusTextField) addSubview(setStatusButton) } private func setupConstraints() { NSLayoutConstraint.activate([ profileNameLabel.topAnchor.constraint(equalTo: topAnchor, constant: 27), profileNameLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 20), profileNameLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), profileNameLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 30), profileStatusLabel.topAnchor.constraint(equalTo: profileNameLabel.bottomAnchor, constant: 10), profileStatusLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 20), profileStatusLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), profileStatusLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 49), statusTextField.topAnchor.constraint(equalTo: profileStatusLabel.bottomAnchor, constant: 10), statusTextField.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 20), statusTextField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), statusTextField.heightAnchor.constraint(equalToConstant: 40), setStatusButton.topAnchor.constraint(equalTo: statusTextField.bottomAnchor, constant: 16), setStatusButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), setStatusButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), setStatusButton.heightAnchor.constraint(equalToConstant: 50), bottomAnchor.constraint(equalTo: setStatusButton.bottomAnchor, constant: 16), ]) } @objc private func statusTextChanged(_ textField: UITextField) { statusText = statusTextField.text! } @objc private func buttonAction() { guard statusTextField.text != nil else { print("Text the status before press the button") return } profileStatusLabel.text = statusText profileStatusLabel.updateConstraintsIfNeeded() self.setNeedsUpdateConstraints() self.layoutIfNeeded() } override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .systemGray4 setupView() setupConstraints() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
MyCustomHeader: UITableViewHeaderFooterView
import UIKit class MyCustomHeader: UITableViewHeaderFooterView { var profileHeaderView = ProfileHeaderView() override init(reuseIdentifier: String?) { super.init(reuseIdentifier: reuseIdentifier) configureContents() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func configureContents() { contentView.addSubview(profileHeaderView) profileHeaderView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ contentView.leadingAnchor.constraint(equalTo: profileHeaderView.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: profileHeaderView.trailingAnchor), contentView.widthAnchor.constraint(equalTo: profileHeaderView.widthAnchor), contentView.heightAnchor.constraint(equalTo: profileHeaderView.heightAnchor), contentView.topAnchor.constraint(equalTo: profileHeaderView.topAnchor), ]) } }
ProfileViewController
import UIKit class ProfileViewController: UIViewController, UIGestureRecognizerDelegate { let postList = [robberyPost, eatingPost, elephantPost, camelPost] var profileTableView = UITableView() let myCustomHeader = MyCustomHeader() let headerID = "headerId" let headerID2 = "headerId2" let cellID = "cellId" let collectionCellID = "collectionCellId" ... func setupTableView() { profileTableView.contentInsetAdjustmentBehavior = .never profileTableView.register(PhotosTableViewCell.self, forCellReuseIdentifier: PhotosTableViewCell.cellID) profileTableView.register(PostTableViewCell.self, forCellReuseIdentifier: PostTableViewCell.cellID) profileTableView.delegate = self profileTableView.dataSource = self profileTableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(profileTableView) } func setupMyCustomHeader() { profileTableView.register(MyCustomHeader.self, forHeaderFooterViewReuseIdentifier: headerID) } private func setupConstraints() { NSLayoutConstraint.activate([ profileTableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), profileTableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), profileTableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), profileTableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), ]) } ... override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemGray6 setupTableView() setupMyCustomHeader() setupConstraints() } } extension ProfileViewController: UITableViewDelegate, UITableViewDataSource { // MARK: - Table view data source ... // MARK: - Table view delegate ... func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { if #available(iOS 15, *) { tableView.sectionHeaderTopPadding = 0 } if section == 0 { return UITableView.automaticDimension } else { return 50 } } func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { if section == 0 { let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerID) as! MyCustomHeader let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(profileImageViewClicked(_ :))) tapRecognizer.numberOfTapsRequired = 1 tapRecognizer.numberOfTouchesRequired = 1 tapRecognizer.delegate = self header.profileHeaderView.profileImageView.isUserInteractionEnabled = true header.profileHeaderView.profileImageView.addGestureRecognizer(tapRecognizer) return header } else { let header2 = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerID2) as! OneMoreCustomHeader return header2 } } ... }
尝试过的无效代码
在buttonAction中添加了以下代码,但未生效:
profileStatusLabel.updateConstraintsIfNeeded() self.setNeedsUpdateConstraints() self.layoutIfNeeded()
解决方案
1. 移除profileStatusLabel的高度约束
删除setupConstraints中这一行约束:
// profileStatusLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 49),
固定的高度约束会限制Label自动扩展,即使设置了numberOfLines = 0也无法正常换行。
2. 修改buttonAction方法
更新文本后,需要通知TableView重新计算Header高度:
@objc private func buttonAction() { guard let newStatus = statusTextField.text, !newStatus.isEmpty else { print("请先输入状态文本") return } profileStatusLabel.text = newStatus // 让Label重新计算自身尺寸 profileStatusLabel.sizeToFit() // 强制更新当前视图布局 self.layoutIfNeeded() // 找到所属TableView,触发高度重新计算 if let tableView = self.superview?.superview as? UITableView { tableView.beginUpdates() tableView.endUpdates() } }
beginUpdates()和endUpdates()会让TableView重新计算所有自动尺寸的元素,包括Header。
3. 修复statusText初始化问题
原代码的lazy初始化会导致无限递归,修改为:
private var statusText: String = ""
内容的提问来源于stack exchange,提问作者Алан Хайманов
相关产品推荐
相关产品推荐

