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

Swift 4中隐藏键盘后底部按钮消失问题的原因及解决方法

问题分析与解决方案:双击隐藏键盘后底部按钮消失

嘿,我来帮你拆解这个问题的原因,然后给你两种可行的解决办法:

为什么双击后底部按钮会消失?

你的代码逻辑里有两个关键问题导致了这个现象:

  • 错误的键盘尺寸获取键:你用了UIKeyboardFrameBeginUserInfoKey来获取键盘尺寸,但这个键对应的是键盘动画开始时的frame。在触发keyboardWillHide时(尤其是双击textView触发的场景),这个值可能无法正确返回键盘的实际高度,导致你给view计算的高度出现偏差——要么把view拉得太长,按钮被挤出屏幕下方;要么拉得太短,按钮被上方内容覆盖。
  • 直接修改view.frame的风险:你直接调整了self.view的frame,而没有遵循Auto Layout的布局逻辑。当通过双击隐藏键盘时,系统的布局更新可能和你的手动frame修改冲突,导致按钮的位置被错误计算,最终看起来像是消失了。

解决办法

方案一:修复键盘尺寸逻辑,恢复view原始高度

这个方案是在你现有代码的基础上修改,不需要调整布局方式:

  1. 首先在ViewController里添加一个变量,保存view的初始高度:
var originalViewHeight: CGFloat = 0
  1. 在viewDidLoad里初始化这个变量:
override func viewDidLoad() {
    super.viewDidLoad()
    originalViewHeight = self.view.frame.height
    // 你的其他代码:添加通知、手势等
}
  1. 修改键盘通知的处理方法,改用UIKeyboardFrameEndUserInfoKey获取键盘最终尺寸,并在隐藏时直接恢复原始高度:
@objc func keyboardWillShow(notification: NSNotification) {
    guard let keyboardEndFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
          let window = self.view.window else {
        return
    }
    // 计算键盘实际占用的高度(适配屏幕旋转)
    let keyboardHeight = window.convert(keyboardEndFrame, to: view).height
    self.view.frame = CGRect(x: view.frame.origin.x, y: view.frame.origin.y, width: view.frame.width, height: originalViewHeight - keyboardHeight)
}

@objc func keyboardWillHide(notification: NSNotification) {
    // 直接恢复view的初始高度,不需要依赖键盘尺寸
    self.view.frame = CGRect(x: view.frame.origin.x, y: view.frame.origin.y, width: view.frame.width, height: originalViewHeight)
}

方案二:推荐使用Auto Layout约束调整(更稳定优雅)

直接修改frame的方式在复杂布局下容易出问题,更推荐用约束来控制底部按钮的位置:

  1. 先给底部按钮的底部添加一个布局约束(可以在Storyboard里拖线,或者代码创建),并关联到ViewController:
@IBOutlet weak var bottomButtonConstraint: NSLayoutConstraint!
var originalConstraintConstant: CGFloat = 0
  1. 在viewDidLoad里保存约束的初始值,同时更新通知的写法(Swift 4+更简洁的写法):
override func viewDidLoad() {
    super.viewDidLoad()
    originalConstraintConstant = bottomButtonConstraint.constant
    
    // 添加键盘通知
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
    
    // 双击手势(记得设置点击次数)
    let tap = UITapGestureRecognizer(target: self, action: #selector(hideKeyBoard))
    tap.numberOfTapsRequired = 2
    statusTextView.addGestureRecognizer(tap)
}
  1. 修改键盘通知的处理逻辑,通过调整约束值来适配键盘:
@objc func keyboardWillShow(notification: NSNotification) {
    guard let keyboardEndFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
          let animationDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? TimeInterval else {
        return
    }
    let keyboardHeight = view.convert(keyboardEndFrame, to: nil).height
    // 调整约束,让按钮上移键盘高度
    bottomButtonConstraint.constant = originalConstraintConstant + keyboardHeight
    // 和键盘动画保持同步
    UIView.animate(withDuration: animationDuration) {
        self.view.layoutIfNeeded()
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    guard let animationDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? TimeInterval else {
        return
    }
    // 恢复约束初始值
    bottomButtonConstraint.constant = originalConstraintConstant
    UIView.animate(withDuration: animationDuration) {
        self.view.layoutIfNeeded()
    }
}

小补充

你原来的双击手势没有设置numberOfTapsRequired = 2,这样单击也会触发隐藏键盘,建议加上这个属性,避免误操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:49:32