iOS中键盘收起后如何让UIButton回到原位置并解决约束崩溃问题
问题原因
你遇到的崩溃是confirmButtonBottomConstrains隐式解包失败导致的,根本原因如下:
- 当你执行
othersTextField.inputAccessoryView = confirmButton时,系统会自动将confirmButton从它原本所在的父视图中移除,挂载到键盘的视图层级下 - 原本绑定在
confirmButton和父视图之间的底部约束confirmButtonBottomConstrains,因为约束的其中一端视图已经脱离父视图,会被系统自动销毁,你存储的约束变量就会变成nil - 键盘收起时你直接访问这个已经变成nil的隐式可选约束,就触发了强制解包崩溃
修复方案
步骤1:调整键盘收起逻辑
先将按钮重新加回父视图,再操作约束,如果约束已经销毁就重新创建:
@objc func keyboardWillHide(_ notification: Notification) { othersTextField.inputAccessoryView = nil // 先把按钮加回原父视图,如果按钮原父视图不是self.view请自行替换 self.view.addSubview(confirmButton) confirmButton.layer.cornerRadius = 20.0 // 恢复按钮原始圆角 // 先判空,如果约束已经销毁就重新创建 if confirmButtonBottomConstrains == nil { // 移除按钮旧的位置约束避免冲突 confirmButton.constraints.forEach { constraint in if [.bottom, .leading, .trailing, .height].contains(constraint.firstAttribute) { confirmButton.removeConstraint(constraint) } } confirmButton.translatesAutoresizingMaskIntoConstraints = false // 补充按钮的水平、高度约束,数值和你原始布局保持一致即可 confirmButton.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 16).isActive = true confirmButton.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -16).isActive = true confirmButton.heightAnchor.constraint(equalToConstant: 40).isActive = true // 重新创建底部约束并赋值 confirmButtonBottomConstrains = confirmButton.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -57) confirmButtonBottomConstrains.isActive = true } else { confirmButtonBottomConstrains.constant = 57 } let userInfo = notification.userInfo let animationDuration = userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as! Double UIView.animate(withDuration: animationDuration) { self.view.layoutIfNeeded() } }
步骤2:优化属性声明
把confirmButtonBottomConstrains的声明从隐式解包类型NSLayoutConstraint!改成普通可选类型NSLayoutConstraint?,避免意外解包崩溃。
可选优化方案
如果按钮样式固定,你也可以直接创建两个相同的按钮实例:一个固定在屏幕底部,一个专门作为inputAccessoryView使用,两个按钮绑定同一个点击事件即可,不需要来回移动视图,逻辑更简单不容易出错。
内容的提问来源于stack exchange,提问作者JOhn Mic
相关产品推荐
相关产品推荐

