如何监听UITableViewCell中UITextField的resignFirstResponder事件并实现警告显示与表格高度动态刷新
Hey there! Let's fix up your cell to meet the validation and height refresh requirements. Your current UI setup is solid, but we need to add text field event handling, validation logic, and a way to tell the table view to update the cell's height when the warning label shows up.
Step 1: Make the Cell Handle Text Field Events
First, we'll have the cell adopt UITextFieldDelegate to detect when the second text field resigns its first responder. We'll also add a closure to notify the parent table view when the validation state changes (so it can refresh the cell height).
Step 2: Add Input Validation Logic
We'll check if both fields are empty when the second text field finishes editing, and add an extra handler to hide the warning label automatically if the user starts typing in either field.
Step 3: Adjust Constraints for Dynamic Height
The warning label needs a bottom constraint tied to the cell's content view—this way, its visibility will automatically adjust the cell's total height.
Full Modified Code
import Foundation import UIKit import SnapKit class TwoTextInputTableViewCell: UITableViewCell, UITextFieldDelegate { let firstTextField = UITextField() let secondTextField = UITextField() let stackView = UIStackView().then { $0.axis = .horizontal $0.distribution = .fillEqually $0.spacing = 15 } let warningLabel = UILabel().then { $0.isHidden = true $0.addCharacterSpacing(-0.1) $0.font = .systemFont(ofSize: 12) $0.textColor = UIColor.CommonColor.salmonColor $0.text = "Please fill in at least one field!" // Don't forget to set your actual warning text } // Closure to notify parent table view of validation state changes var onValidationStateChanged: (() -> Void)? required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupTextFieldConfig() } override init(style: UITableViewCell.CellStyle, reuseIdentifier: String!) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupSubviewsAndConstraints() setupTextFieldConfig() } private func setupSubviewsAndConstraints() { contentView.addSubviews(stackView, warningLabel) stackView.addArrangedSubview(firstTextField) stackView.addArrangedSubview(secondTextField) stackView.snp.makeConstraints { $0.left.equalToSuperview().offset(24) $0.right.equalToSuperview().offset(-24) $0.top.equalToSuperview().offset(12) $0.height.equalTo(56) } warningLabel.snp.makeConstraints { $0.top.equalTo(stackView.snp.bottom).offset(12) $0.height.equalTo(16) $0.left.right.equalTo(stackView) $0.bottom.equalToSuperview().offset(-12) // Critical: ties warning label to cell bottom } } private func setupTextFieldConfig() { firstTextField.delegate = self secondTextField.delegate = self // Add text change handlers to auto-hide warning when user types firstTextField.addTarget(self, action: #selector(textFieldTextChanged), for: .editingChanged) secondTextField.addTarget(self, action: #selector(textFieldTextChanged), for: .editingChanged) } // MARK: - UITextFieldDelegate func textFieldDidEndEditing(_ textField: UITextField) { // Only trigger validation when the second text field resigns first responder guard textField == secondTextField else { return } validateInputFields() } // MARK: - Input Validation @objc private func textFieldTextChanged() { validateInputFields() } private func validateInputFields() { // Trim whitespace to avoid treating empty spaces as valid content let firstIsEmpty = firstTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true let secondIsEmpty = secondTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true let shouldShowWarning = firstIsEmpty && secondIsEmpty warningLabel.isHidden = !shouldShowWarning // Notify parent table view to update cell height onValidationStateChanged?() } }
Step 4: Configure the Parent Table View
In your view controller, enable automatic row heights and set up the closure to trigger smooth height updates:
class YourViewController: UIViewController { @IBOutlet weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() // Enable automatic cell height calculation tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 100 // Set a reasonable estimated height tableView.register(TwoTextInputTableViewCell.self, forCellReuseIdentifier: "TwoTextInputCell") } } extension YourViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TwoTextInputCell", for: indexPath) as! TwoTextInputTableViewCell // Set up closure to refresh cell height when validation state changes cell.onValidationStateChanged = { [weak self] in // Animate height changes smoothly self?.tableView.beginUpdates() self?.tableView.endUpdates() } return cell } }
Key Notes:
- We trim whitespace from text field inputs to ensure empty spaces don't count as valid content.
- The
onValidationStateChangedclosure keeps the cell decoupled from the table view while enabling height updates. - Using
beginUpdates()andendUpdates()ensures the table view recalculates the cell's height with a smooth animation.
内容的提问来源于stack exchange,提问作者Ho Si Tuan

