Swift 4中隐藏键盘后底部按钮消失问题的原因及解决方法
问题分析与解决方案:双击隐藏键盘后底部按钮消失
嘿,我来帮你拆解这个问题的原因,然后给你两种可行的解决办法:
为什么双击后底部按钮会消失?
你的代码逻辑里有两个关键问题导致了这个现象:
- 错误的键盘尺寸获取键:你用了
UIKeyboardFrameBeginUserInfoKey来获取键盘尺寸,但这个键对应的是键盘动画开始时的frame。在触发keyboardWillHide时(尤其是双击textView触发的场景),这个值可能无法正确返回键盘的实际高度,导致你给view计算的高度出现偏差——要么把view拉得太长,按钮被挤出屏幕下方;要么拉得太短,按钮被上方内容覆盖。 - 直接修改view.frame的风险:你直接调整了
self.view的frame,而没有遵循Auto Layout的布局逻辑。当通过双击隐藏键盘时,系统的布局更新可能和你的手动frame修改冲突,导致按钮的位置被错误计算,最终看起来像是消失了。
解决办法
方案一:修复键盘尺寸逻辑,恢复view原始高度
这个方案是在你现有代码的基础上修改,不需要调整布局方式:
- 首先在ViewController里添加一个变量,保存view的初始高度:
var originalViewHeight: CGFloat = 0
- 在
viewDidLoad里初始化这个变量:
override func viewDidLoad() { super.viewDidLoad() originalViewHeight = self.view.frame.height // 你的其他代码:添加通知、手势等 }
- 修改键盘通知的处理方法,改用
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的方式在复杂布局下容易出问题,更推荐用约束来控制底部按钮的位置:
- 先给底部按钮的底部添加一个布局约束(可以在Storyboard里拖线,或者代码创建),并关联到ViewController:
@IBOutlet weak var bottomButtonConstraint: NSLayoutConstraint! var originalConstraintConstant: CGFloat = 0
- 在
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) }
- 修改键盘通知的处理逻辑,通过调整约束值来适配键盘:
@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
相关产品推荐
相关产品推荐

