移动视图时安全区域插入消失
Safe Area Insets Disappear when Moving View
在我的 iOS 项目中,我有一个带有几个文本字段的视图控制器。为确保控件在用户输入文本时保持可见,我使用以下代码移动内容并为键盘腾出空间:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
@objc func keyboardWillShow(notification: NSNotification) {
dPrint(tag: "Safe Area", message: "keyboardWillShow()")
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if activeField != nil {
var activeFieldBottomDistance: CGFloat = view.frame.size.height - ... // calculation of position omitted here
let yOffset: CGFloat = activeFieldBottomDistance
- keyboardSize.height
- view.frame.origin.y
if yOffset + view.frame.origin.y < 0 {
moveViewForKeyboard(offset: yOffset)
}
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
dPrint(tag: "Safe Area", message: "keyboardWillHide()")
let yOffset: CGFloat = -view.frame.origin.y
moveViewForKeyboard(offset: yOffset)
}
func moveViewForKeyboard(offset: CGFloat!) {
let duration = 0.3
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(duration)
view.frame = view.frame.offsetBy(dx: 0, dy: offset)
UIView.commitAnimations()
view.setNeedsLayout()
view.layoutIfNeeded()
}
布局如下(stack view里面有text views):
我的问题是,当根视图向上移动以为键盘腾出空间时,安全区域边距会丢失。 例如当横向使用它并且键盘出现时,内容会水平扩展,当键盘再次隐藏时,内容会移回安全区域的边界。
下面的代码会产生下面的输出:
@available(iOS 11.0, *)
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
dPrint(tag: "Safe Area", message: "saveAreaInsetsDidChange")
dPrint(tag: "Safe Area", message: "top: " + String(describing: view.safeAreaInsets.top))
dPrint(tag: "Safe Area", message: "right: " + String(describing: view.safeAreaInsets.right))
dPrint(tag: "Safe Area", message: "bottom: " + String(describing: view.safeAreaInsets.bottom))
dPrint(tag: "Safe Area", message: "left: " + String(describing: view.safeAreaInsets.left))
}
Safe Area saveAreaInsetsDidChange
Safe Area top: 0.0
Safe Area right: 44.0
Safe Area bottom: 21.0
Safe Area left: 44.0
Safe Area keyboardWillShow()
Safe Area saveAreaInsetsDidChange
Safe Area top: 0.0
Safe Area right: 0.0
Safe Area bottom: 0.0
Safe Area left: 0.0
Safe Area keyboardWillHide()
Safe Area saveAreaInsetsDidChange
Safe Area top: 0.0
Safe Area right: 44.0
Safe Area bottom: 21.0
Safe Area left: 44.0
如何移动内容,使其保持在安全区域内,并且它也适用于以 iOS9.[=14= 开头的旧设备]
(我尝试的选项之一是在根视图下方创建一个附加视图层并移动它。这不起作用,因为像对话框一样以模态方式呈现的内容垂直居中。将中心与其他任何内容对齐比根视图不允许内容移动。)
您可以使用 UnderKeyboard 库来实现。
因此,我强烈建议您使用 UIScrollView 在键盘打开时移动您的内容。关注 this guide.
或者使用 AutoLayout 底部约束进行底部填充并动画更改其常量。
示例:
@IBOutlet var bottomConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillHideNotification, object: nil)
}
func animateWithKeyboard(notification: NSNotification) {
let userInfo = notification.userInfo!
let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
let moveUp = (notification.name == UIKeyboardWillShowNotification)
bottomConstraint.constant = moveUp ? -keyboardHeight : 0
let options = UIViewAnimationOptions(rawValue: curve << 16)
UIView.animateWithDuration(duration, delay: 0, options: options, animations: {
self.view.layoutIfNeeded()
},
completion: nil)
}
在我的 iOS 项目中,我有一个带有几个文本字段的视图控制器。为确保控件在用户输入文本时保持可见,我使用以下代码移动内容并为键盘腾出空间:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
@objc func keyboardWillShow(notification: NSNotification) {
dPrint(tag: "Safe Area", message: "keyboardWillShow()")
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if activeField != nil {
var activeFieldBottomDistance: CGFloat = view.frame.size.height - ... // calculation of position omitted here
let yOffset: CGFloat = activeFieldBottomDistance
- keyboardSize.height
- view.frame.origin.y
if yOffset + view.frame.origin.y < 0 {
moveViewForKeyboard(offset: yOffset)
}
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
dPrint(tag: "Safe Area", message: "keyboardWillHide()")
let yOffset: CGFloat = -view.frame.origin.y
moveViewForKeyboard(offset: yOffset)
}
func moveViewForKeyboard(offset: CGFloat!) {
let duration = 0.3
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(duration)
view.frame = view.frame.offsetBy(dx: 0, dy: offset)
UIView.commitAnimations()
view.setNeedsLayout()
view.layoutIfNeeded()
}
布局如下(stack view里面有text views):
我的问题是,当根视图向上移动以为键盘腾出空间时,安全区域边距会丢失。 例如当横向使用它并且键盘出现时,内容会水平扩展,当键盘再次隐藏时,内容会移回安全区域的边界。
下面的代码会产生下面的输出:
@available(iOS 11.0, *)
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
dPrint(tag: "Safe Area", message: "saveAreaInsetsDidChange")
dPrint(tag: "Safe Area", message: "top: " + String(describing: view.safeAreaInsets.top))
dPrint(tag: "Safe Area", message: "right: " + String(describing: view.safeAreaInsets.right))
dPrint(tag: "Safe Area", message: "bottom: " + String(describing: view.safeAreaInsets.bottom))
dPrint(tag: "Safe Area", message: "left: " + String(describing: view.safeAreaInsets.left))
}
Safe Area saveAreaInsetsDidChange
Safe Area top: 0.0
Safe Area right: 44.0
Safe Area bottom: 21.0
Safe Area left: 44.0
Safe Area keyboardWillShow()
Safe Area saveAreaInsetsDidChange
Safe Area top: 0.0
Safe Area right: 0.0
Safe Area bottom: 0.0
Safe Area left: 0.0
Safe Area keyboardWillHide()
Safe Area saveAreaInsetsDidChange
Safe Area top: 0.0
Safe Area right: 44.0
Safe Area bottom: 21.0
Safe Area left: 44.0
如何移动内容,使其保持在安全区域内,并且它也适用于以 iOS9.[=14= 开头的旧设备]
(我尝试的选项之一是在根视图下方创建一个附加视图层并移动它。这不起作用,因为像对话框一样以模态方式呈现的内容垂直居中。将中心与其他任何内容对齐比根视图不允许内容移动。)
您可以使用 UnderKeyboard 库来实现。
因此,我强烈建议您使用 UIScrollView 在键盘打开时移动您的内容。关注 this guide.
或者使用 AutoLayout 底部约束进行底部填充并动画更改其常量。
示例:
@IBOutlet var bottomConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillHideNotification, object: nil)
}
func animateWithKeyboard(notification: NSNotification) {
let userInfo = notification.userInfo!
let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
let moveUp = (notification.name == UIKeyboardWillShowNotification)
bottomConstraint.constant = moveUp ? -keyboardHeight : 0
let options = UIViewAnimationOptions(rawValue: curve << 16)
UIView.animateWithDuration(duration, delay: 0, options: options, animations: {
self.view.layoutIfNeeded()
},
completion: nil)
}