如何设置StackView与TableViewCell内TextView的动态高度?
问题描述
开发待办事项App时遇到TextView高度设置问题,需求如下:
- TextView基础高度不小于50
- 高度随内容自动动态调整
已尝试isScrollEnabled = false、.sizeToFit()、translatesAutoresizingMaskIntoConstraints = true等方案,仍未解决,相关代码如下:
class ToDoTableViewCell: UITableViewCell, UITextViewDelegate { lazy var backColorView: UIView = { let view = UIView() view.backgroundColor = .yellow view.translatesAutoresizingMaskIntoConstraints = false return view }() let memoString: UITextView = { let textView = UITextView() textView.font = .systemFont(ofSize: 17, weight: .regular) textView.layer.cornerRadius = 0 textView.layer.borderWidth = 1 textView.layer.borderColor = #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1) textView.backgroundColor = .clear textView.isS return textView }() let dateString: UILabel = { let date = UILabel() date.font = .systemFont(ofSize: 14, weight: .light) date.text = "2021-11-12" return date }() let updateButton: UIButton = { let button = UIButton() button.setTitle("UPDATE", for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = .systemFont(ofSize: 9, weight: .bold) button.layer.cornerRadius = 10 button.backgroundColor = .gray button.setImage(UIImage(systemName: "pencil"), for: .normal) return button }() let totalStackView: UIStackView = { let stack = UIStackView() stack.axis = .vertical stack.distribution = .fill stack.alignment = .fill stack.spacing = 10 return stack }() let subStackView: UIStackView = { let stack = UIStackView() stack.axis = .horizontal stack.distribution = .fill stack.alignment = .fill stack.spacing = 0 return stack }() override func awakeFromNib() { super.awakeFromNib() memoString.delegate = self } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: .default, reuseIdentifier: reuseIdentifier) setupStackView() setConstraints() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func setupStackView() { self.contentView.addSubview(backColorView) totalStackView.addArrangedSubview(memoString) totalStackView.addArrangedSubview(subStackView) subStackView.addArrangedSubview(dateString) subStackView.addArrangedSubview(updateButton) self.contentView.addSubview(totalStackView) } func setConstraints() { totalStackView.translatesAutoresizingMaskIntoConstraints = false subStackView.translatesAutoresizingMaskIntoConstraints = false updateButton.translatesAutoresizingMaskIntoConstraints = false memoString.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ totalStackView.leadingAnchor.constraint(equalTo: backColorView.leadingAnchor, constant: 10), totalStackView.trailingAnchor.constraint(equalTo: backColorView.trailingAnchor, constant: -10), totalStackView.topAnchor.constraint(equalTo: backColorView.topAnchor, constant: 10), totalStackView.bottomAnchor.constraint(equalTo: backColorView.bottomAnchor, constant: -10), subStackView.heightAnchor.constraint(equalToConstant: 30), updateButton.widthAnchor.constraint(equalToConstant: 80), backColorView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 25), backColorView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -25), backColorView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 10), backColorView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -10), memoString.heightAnchor.constraint(greaterThanOrEqualToConstant: 50) ]) } }
class ViewController: UIViewController { private let tableView = UITableView() override func viewDidLoad() { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self subviews() constraints() setupTableView() makeUI() makeButton() } func setupTableView() { tableView.translatesAutoresizingMaskIntoConstraints = false tableView.register(ToDoTableViewCell.self, forCellReuseIdentifier: "cell") } } extension ViewController { func makeUI() { let navigationBarAppearance = UINavigationBarAppearance() navigationBarAppearance.configureWithOpaqueBackground() navigationController?.navigationBar.standardAppearance = navigationBarAppearance navigationController?.navigationBar.scrollEdgeAppearance = navigationBarAppearance navigationController?.navigationBar.tintColor = .blue navigationItem.scrollEdgeAppearance = navigationBarAppearance navigationItem.standardAppearance = navigationBarAppearance navigationItem.compactAppearance = navigationBarAppearance navigationController?.setNeedsStatusBarAppearanceUpdate() navigationController?.navigationBar.isTranslucent = false navigationController?.navigationBar.prefersLargeTitles = true title = "메모" } func makeButton() { let button = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(action)) navigationItem.rightBarButtonItem = button } @objc func action() {} func subviews() { view.addSubview(tableView) } func constraints() { NSLayoutConstraint.activate([ tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.leftAnchor.constraint(equalTo: view.leftAnchor), tableView.rightAnchor.constraint(equalTo: view.rightAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } } extension ViewController: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 5 } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) return cell } }
解决方案
针对需求,调整以下关键设置即可解决问题:
1. 修复TextView初始化代码
初始化时关闭滚动功能(核心设置,否则TextView不会自动调整高度),同时补全语法错误:
let memoString: UITextView = { let textView = UITextView() textView.font = .systemFont(ofSize: 17, weight: .regular) textView.layer.cornerRadius = 0 textView.layer.borderWidth = 1 textView.layer.borderColor = #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1) textView.backgroundColor = .clear // 关闭滚动,允许高度自动扩展 textView.isScrollEnabled = false textView.translatesAutoresizingMaskIntoConstraints = false return textView }()
2. 完善TableView自动高度配置
添加预估行高,确保自动维度生效:
func setupTableView() { tableView.translatesAutoresizingMaskIntoConstraints = false tableView.register(ToDoTableViewCell.self, forCellReuseIdentifier: "cell") // 配置自动行高与预估高度 tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 100 }
3. 内容变化时刷新行高
实现TextView代理方法,当内容修改时通知TableView更新当前行高度:
在ToDoTableViewCell中添加:
// 添加弱引用获取所在TableView weak var tableView: UITableView? func textViewDidChange(_ textView: UITextView) { // 触发行高更新 tableView?.beginUpdates() tableView?.endUpdates() }
然后在ViewController的cellForRowAt方法中绑定引用:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ToDoTableViewCell cell.tableView = tableView // 可设置测试文本验证效果 cell.memoString.text = "测试文本\n多行内容\n验证高度是否自动调整" return cell }
4. 保留现有约束
你已设置memoString.heightAnchor.constraint(greaterThanOrEqualToConstant: 50),该约束满足“基础高度不小于50”的需求,无需修改。
完成以上修改后,TextView会在内容较少时保持50高度,内容增多时自动扩展,同时TableView行高也会同步调整。
内容的提问来源于stack exchange,提问作者피우리
相关产品推荐
相关产品推荐

