Swift - 键盘出现后自动改变页面布局,防止下方元素被键盘遮挡
作者:hangge | 2015-10-28 07:15
(本文代码已升级至Swift4)
比如我在页面下方添加了一个 toolBar,toolBar 里面有输入框。同时给 toolBar 添加个约束,使其一直在页面底部。

可以看到虚拟键盘上移后,把 toolBar 给遮挡住了。

解决办法:
监听键盘通知(UIKeyboardWillChangeFrame),当键盘出现或者隐藏时我们动态改变 View 的高度,位置等,实现自适应布局。本例便是改变 toolBar 的下约束,就算键盘出现,toolBar 也能在键盘的上方。
(注:键盘出现、隐藏的过程中,toolBar 上下移动是跟随着键盘有动画效果的)
代码如下:
代码如下:
import UIKit
class ViewController: UIViewController {
//toolBar的下约束
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(ViewController.keyboardWillChange(_:)),
name: .UIKeyboardWillChangeFrame, object: nil)
}
// 键盘改变
@objc func keyboardWillChange(_ notification: Notification) {
if let userInfo = notification.userInfo,
let value = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue,
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt {
let frame = value.cgRectValue
let intersection = frame.intersection(self.view.frame)
//self.view.setNeedsLayout()
//改变下约束
self.bottomConstraint.constant = -intersection.height
UIView.animate(withDuration: duration, delay: 0.0,
options: UIViewAnimationOptions(rawValue: curve), animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
}
@IBAction func sendMessage(_ sender: AnyObject) {
//关闭键盘
textField.resignFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
效果图如下:

全部评论(7)
感谢站长,学习了
站长回复:不客气,欢迎常来看看,我会持续更新下去的。
站長,有swift4版本嗎?
站长回复:代码已更新,你可以再看下。
站長,現在是不是沒有bottomConstraint,現在View不是自帶Safe Area,還能用bottomConstraint嗎?
站长回复:bottomConstraint 还是有的,你大概是把它和 bottomLayoutGuide 给混淆了。iOS11 中引入的 Safe Area 是取代原先的 topLayoutGuide 和 bottomLayoutGuide。
改成self.view.layoutIfNeeded()以后还是不行?
站长回复:那我也不清楚是什么问题了,我这边又测试了下是好的。
你好,我的还是没有动画效果,我用的storyboard是不是有关系? 下面是我的代码
func keyboardWillChange(notification:NSNotification){
if let userInfo = notification.userInfo,
value = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue,
duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt {
let frame = value.CGRectValue()
let intersection = CGRectIntersection(frame, self.view.frame)
//改变下约束
self.stackViewBot.constant = CGRectGetHeight(intersection)
UIView.animateWithDuration(duration, delay: 0.0,
options: UIViewAnimationOptions(rawValue: curve), animations: {
_ in
self.view.setNeedsLayout()
}, completion: nil)
}
}
站长回复:我把self.view.setNeedsLayout()改成self.view.layoutIfNeeded()了,你试试看
你好为什么没有动画效果呢?
站长回复:我把代码修改了下,你再试试看。
如何直接通过代码的形式给输入框添加约束呢?
站长回复:用代码设置约束也是可以的,就是麻烦些。可以参考我的这篇文章:http://www.hangge.com/blog/cache/detail_746.html