Swift4中解决UITextField被iOS键盘遮挡时的滚动问题
Swift4 搞定底部UITextField被键盘遮挡的问题
嘿,我刚好在Swift4里踩过这个坑,给你分享两个亲测有效的方案,帮你解决键盘挡住底部输入框的问题!先看你的界面情况:
全屏状态:
键盘遮挡后的状态:
你之前提到的那篇文章报错,是因为没正确关联contentView的高度约束,我下面也会专门讲这个问题的解决办法。
方案一:普通视图(没有用UIScrollView)
如果你的界面没有滚动视图,直接调整输入框的底部约束就行:
- 首先在Storyboard里给底部UITextField加一个底部约束,然后把这个约束拖成ViewController里的IBOutlet,比如叫
textFieldBottomConstraint。 - 注册键盘弹出/收起的通知,动态调整约束值:
class ViewController: UIViewController { @IBOutlet weak var textFieldBottomConstraint: NSLayoutConstraint! @IBOutlet weak var bottomTextField: UITextField! override func viewDidLoad() { super.viewDidLoad() // 注册键盘通知(Swift4用UIResponder的静态属性,比旧版更规范) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) } // 键盘弹出时调整约束 @objc func keyboardWillShow(notification: NSNotification) { guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return } let keyboardHeight = keyboardFrame.height // 把底部约束改成键盘高度加个小间距(比如16),避免输入框贴键盘太近 textFieldBottomConstraint.constant = keyboardHeight + 16 // 用动画更新布局,过渡更自然 UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } // 键盘收起时恢复原约束 @objc func keyboardWillHide(notification: NSNotification) { textFieldBottomConstraint.constant = 16 // 这里改成你原来的底部间距 UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } // 记得销毁时移除通知,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) } }
方案二:用UIScrollView的情况(解决你之前的报错)
你之前遇到的self.constraintContentHeight.constant不是ViewController成员错误,是因为你没有把contentView的高度约束关联到ViewController里。按下面步骤来:
正确设置ScrollView的AutoLayout:
- 给ScrollView加约束:上下左右都和父视图边缘对齐。
- 在ScrollView里添加一个contentView(UIView),给contentView加约束:上下左右都和ScrollView的contentLayoutGuide对齐,同时contentView的宽度等于父视图的宽度(避免横向滚动)。
- 给contentView加一个高度约束,这个约束就是我们要关联的
constraintContentHeight。
关联约束IBOutlet:在ViewController里声明
@IBOutlet weak var constraintContentHeight: NSLayoutConstraint!,然后在Storyboard里把contentView的高度约束拖到这个变量上。然后同样用通知调整约束或者滚动位置:
class ViewController: UIViewController { @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var constraintContentHeight: NSLayoutConstraint! @IBOutlet weak var bottomTextField: UITextField! override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) // 如果要在编辑时自动滚动,记得设置输入框代理 bottomTextField.delegate = self } @objc func keyboardWillShow(notification: NSNotification) { guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return } let keyboardHeight = keyboardFrame.height // 方法一:调整contentView高度,让输入框能被滚动到 constraintContentHeight.constant = self.view.frame.height + keyboardHeight // 方法二:直接滚动到输入框位置(更精准) let textFieldFrame = bottomTextField.frame scrollView.scrollRectToVisible(textFieldFrame, animated: true) } @objc func keyboardWillHide(notification: NSNotification) { // 恢复contentView高度 constraintContentHeight.constant = self.view.frame.height // 滚动回顶部 scrollView.setContentOffset(CGPoint.zero, animated: true) } deinit { NotificationCenter.default.removeObserver(self) } } // 加上输入框代理,编辑时自动滚动 extension ViewController: UITextFieldDelegate { func textFieldDidBeginEditing(_ textField: UITextField) { let point = textField.convert(CGPoint.zero, to: scrollView) // 滚动到输入框上方,留16间距 scrollView.setContentOffset(CGPoint(x: 0, y: point.y - 16), animated: true) } func textFieldDidEndEditing(_ textField: UITextField) { scrollView.setContentOffset(CGPoint.zero, animated: true) } }
这样就不会再出现之前的错误了,因为constraintContentHeight已经被正确关联到Storyboard的约束上啦!
内容的提问来源于stack exchange,提问作者Augusto
相关产品推荐
相关产品推荐

