You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 4中如何动态修改代码创建的自定义inputAccessoryView高度?

解决消息应用输入框高度随文本行数动态增加的动画问题

嘿,刚好我之前做过类似的消息输入框需求,给你一步步拆解怎么实现:

核心思路

因为typingView是作为主视图的inputAccessoryView,系统对它的布局有特殊管理,所以我们需要通过监听文本框内容变化,计算所需高度,更新约束并配合动画触发布局更新,而且只处理高度增加的情况(你说暂不考虑减少,那我们就只做增量判断)。

具体实现步骤

1. 先做好基础配置

首先确保你的messageTextView已经设置好代理,并且关闭滚动(这样文本内容超出一行时,才会让整个输入框增高,而不是文本框内部滚动):

override func viewDidLoad() {
    super.viewDidLoad()
    messageTextView.delegate = self
    messageTextView.isScrollEnabled = false
    // 记得给typingViewHeight设置初始值,比如等于文本框默认高度+上下内边距
    typingViewHeight?.constant = (messageTextView.font?.lineHeight ?? 20) + 16 // 16是上下padding
}

2. 监听文本内容变化,计算并更新高度

实现UITextViewDelegate的textViewDidChange方法,在这里处理高度计算和动画:

extension YourViewController: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        // 计算文本框刚好容纳内容的高度,sizeThatFits会自动考虑字体、行间距等
        let requiredHeight = textView.sizeThatFits(
            CGSize(width: textView.bounds.width, height: CGFloat.greatestFiniteMagnitude)
        ).height
        
        // 只处理高度增加的情况
        guard let currentHeight = typingViewHeight?.constant, requiredHeight > currentHeight else {
            return
        }
        
        // 更新约束值
        typingViewHeight?.constant = requiredHeight
        
        // 执行动画,这里的关键是在动画块里调用layoutIfNeeded触发布局更新
        UIView.animate(withDuration: 0.2, curve: .easeInOut) {
            self.typingView.layoutIfNeeded()
            self.view.layoutIfNeeded()
            // 额外保险:如果系统没自动更新inputAccessoryView,触发一下响应状态切换
            self.becomeFirstResponder()
            self.resignFirstResponder()
        }
    }
}

3. 确保输入框内部布局正确

你的typingView内部布局要做好绑定,比如:

  • messageTextView的上下左右约束和typingView绑定(留好内边距)
  • sendButton固定在右下角(比如右内边距、垂直居中,高度宽度固定)
    这样当typingView高度增加时,messageTextView会自动扩展高度,按钮位置保持不变。

关键注意点

  • 一定要关闭messageTextView的滚动:isScrollEnabled = false,否则文本框会自己滚动,不会触发整个输入框增高
  • 用sizeThatFits计算高度是最准确的,它会根据文本框的当前样式(字体、行间距、内边距)计算刚好容纳内容的高度
  • 动画块里必须调用layoutIfNeeded,否则约束变化不会有动画效果
  • 最后触发becomeFirstResponder和resignFirstResponder是为了确保系统正确更新inputAccessoryView的高度,避免出现布局异常

内容的提问来源于stack exchange,提问作者Michael Hsu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:25:17