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

iOS聊天视图控制器UITextField键盘无法正常收起问题求助

排查ChatScreenVC中UITextField键盘无法正常收起的问题

让我帮你一步步梳理这个键盘收起的异常问题,你已经做了不少尝试,不过有几个关键细节可能被忽略了,咱们逐个排查:

1. 最可能的根源:UITextField代理未绑定

你已经实现了UITextFieldDelegate协议和textFieldShouldReturn方法,但在viewDidLoad里没有设置chatInput.delegate = self!这会导致:

  • 点击键盘的返回键时,textFieldShouldReturn根本不会被调用(你打印的"THIS IS HAPPENING!"应该也没在控制台输出吧?)
  • 代理方法失效后,键盘的默认返回收起逻辑也无法触发

修复方案:在viewDidLoad中添加一行代码:

override func viewDidLoad() {
    super.viewDidLoad()
    chatLog.text = chatLogString
    chatLog.isEditable = false
    chatInput.autocorrectionType = .no
    // 新增:绑定UITextField代理
    chatInput.delegate = self
}

2. 键盘通知的注册与移除不完整

你在viewDidDisappear里只移除了UIKeyboardWillShow的通知,但没有移除UIKeyboardWillHide的通知,这会导致通知残留,可能干扰键盘的正常状态。另外,建议把通知注册移到viewWillAppear,移除移到viewWillDisappear,更符合ViewController的生命周期逻辑,避免重复注册。

修复方案:

override func viewWillAppear(_ animated: Bool) {
    setupView()
    animateView()
    // 移到这里注册键盘通知
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    chatInput.resignFirstResponder()
    // 移除所有相关通知
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    // 只保留SMACK_TALK通知的注册
    NotificationCenter.default.addObserver(self, selector: #selector(self.reloadData), name: Notification.Name(rawValue: SMACK_TALK), object: nil)
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: SMACK_TALK), object: nil)
}

3. 优化sendTapped方法的执行逻辑

你在发送按钮点击事件里已经调用了resignFirstResponder和view.endEditing(true),但可以做两个优化确保生效:

  • 用guard更严谨地判断输入内容(过滤空白字符)
  • 确保UI操作在主线程执行(虽然默认是主线程,但避免异步操作干扰)

修复后的sendTapped:

@IBAction func sendTapped(_ sender: Any) {
    // 过滤空白字符,避免空消息或纯空格消息
    guard let message = chatInput.text?.trimmingCharacters(in: .whitespacesAndNewlines), !message.isEmpty else {
        return
    }
    gameDelegate?.sendChat(message: message)
    chatInput.text = ""
    // 确保在主线程执行键盘收起操作
    DispatchQueue.main.async {
        self.chatInput.resignFirstResponder()
        self.view.endEditing(true)
    }
}

4. 完善键盘弹出/收起的布局动画

你修改了viewCenterConstraint来适配键盘,但没有触发布局动画,这可能导致视图更新不及时,间接影响键盘的状态。添加动画和layoutIfNeeded()可以确保布局平滑更新:

修复键盘通知方法:

@objc func keyboardWillShow(_ notification: Notification) {
    if let keyboardFrame: NSValue = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue {
        let keyboardHeight = keyboardFrame.cgRectValue.height
        viewCenterConstraint.constant = -keyboardHeight
        // 触发布局动画
        UIView.animate(withDuration: 0.3) {
            self.view.layoutIfNeeded()
        }
    }
}

@objc func keyboardWillHide(_ notification: Notification) {
    viewCenterConstraint.constant = 0
    // 触发布局动画
    UIView.animate(withDuration: 0.3) {
        self.view.layoutIfNeeded()
    }
}

5. 排查其他潜在干扰

如果以上修复后还是有问题,可以检查:

  • 是否在reloadData或SMACK_TALK通知的回调中,不小心调用了chatInput.becomeFirstResponder()?
  • 有没有其他手势或第三方库拦截了UITextField的响应链?

先从绑定代理这个最基础的步骤开始试,大概率能解决你的问题!

内容的提问来源于stack exchange,提问作者dvd.Void

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:50:40