XIB加载的UITextView如何实现类似WhatsApp的随内容自适应高度效果?
问题根因及修复方案
存在的核心问题
- 你已经在XIB中关联了高度约束的IBOutlet
textViewHC,但又在viewDidLoad中额外新增了一个高度为52的高度约束,两个高度约束冲突导致高度修改不生效 - 遍历所有约束修改高度的逻辑冗余,也可能误改其他约束,直接操作已关联的
textViewHC即可 - 修改高度约束后没有触发父视图的布局刷新,你的输入视图加载在容器视图中,必须通知父视图更新布局才能让整体容器同步适配高度
- 初始状态没有关闭
isScrollEnabled,初始状态下如果没关闭的话自适应逻辑不会生效
修改后的代码
class InputTextViewController: UIViewController{ @IBOutlet weak var inputTitle: UILabel! @IBOutlet weak var border: UIView! @IBOutlet weak var inputTextView: UITextView! @IBOutlet weak var underText: UILabel! @IBOutlet weak var underLine: UIView! @IBOutlet weak var textViewHC: NSLayoutConstraint! // 高度常量统一配置,方便后续修改 private let maxTextViewHeight: CGFloat = 100.0 private let minTextViewHeight: CGFloat = 52.0 override func viewDidLoad() { super.viewDidLoad() // 删掉多余的新增高度约束,直接用已有的IBOutlet约束设置初始高度 textViewHC.constant = minTextViewHeight self.inputTextView.delegate = self // 初始关闭滚动,开启自适应 inputTextView.isScrollEnabled = false inputTextView.translatesAutoresizingMaskIntoConstraints = false } } extension InputTextViewController: UITextViewDelegate{ func textViewDidChange(_ textView: UITextView) { let size = CGSize(width: inputTextView.frame.size.width, height: .infinity) let estimatedSize = inputTextView.sizeThatFits(size) let targetHeight = min(estimatedSize.height, maxTextViewHeight) // 高度无变化时跳过更新,避免重复布局 guard textViewHC.constant != targetHeight else { return } textViewHC.constant = targetHeight // 超过最大高度开启滚动,否则关闭 inputTextView.isScrollEnabled = estimatedSize.height >= maxTextViewHeight // 触发当前视图和父容器的布局更新,加动画更流畅 UIView.animate(withDuration: 0.2) { [weak self] in self?.view.layoutIfNeeded() self?.parent?.view.layoutIfNeeded() } } }
额外需要检查的配置
- 确认你的容器视图对
InputTextViewController的根视图的约束是四边贴合,没有固定高度约束,否则容器不会随输入视图高度变化 - 确认
inputTextView在XIB中的上下左右约束已经正确关联到父视图,只保留关联到textViewHC的那一个高度约束即可,删除其他多余的高度约束 - 如果输入框有内边距需求,可以统一设置
inputTextView.textContainerInset调整,不要用额外的空白约束修改高度
内容的提问来源于stack exchange,提问作者LgSus97
相关产品推荐
相关产品推荐

