如何将底部视图移动到UIKeyboard顶部

问题描述:

您好我正在尝试使视图的底部与UIKeyboard的顶部对齐。如何将底部视图移动到UIKeyboard顶部

更新1:我创建了一个GitHub的项目,如果你想给它一个尝试:https://github.com/JCzz/KeyboardProject

注:我需要的aView是动态的。

更新2:只是推 - 包括使用框架

我可能一直在寻找这个时间太长,我不能换我周围的大脑:-)

你知道怎么样?

  1. 我该如何知道UIKeyboard是否处于关闭状态?

  2. 如果UIKeyboard已启动,那么如何将它与视图对齐(attachKeyboardToFrame - 请参阅代码)。

我发现下面的UIView扩展:

import UIKit 

extension UIView { 

    func bindToKeyboard(){ 
     NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) 
    } 

    func unbindFromKeyboard(){ 
     NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) 
    } 

    @objc 
    func keyboardWillChange(notification: NSNotification) { 

     guard let userInfo = notification.userInfo else { return } 

     let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double 
     let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt 
     let curFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue 
     let targetFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue 

     // To get the total height of view 
     let topView = UIApplication.shared.windows.last 
     // 
     let attachKeyboardToFrame = Singleton.sharedInstance.attachKeyboardToFrame 
     let global_attachKeyboardToFrame = self.superview?.convert(attachKeyboardToFrame!, to: topView) 

     if (targetFrame.height + attachKeyboardToFrame!.height) > (topView?.frame.height)! { 
      self.frame.origin.y = -targetFrame.origin.y 
     }else{ 

     } 

    } 
} 
+1

至1:使用UIKeyboardWillShow和UIKeyboardWillHide代替UIKeyboardWillChangeFrame – Michael

+0

另一个谜团是当按下键盘向下箭头时不会调用UIKeyboardWillHide。 –

您可以通过下面的自动布局解决方案实现它。

首先,你需要UILayoutGuide将被用来模拟键盘意识到底部锚和NSLayoutConstraint将控制这个布局指南:

fileprivate let keyboardAwareBottomLayoutGuide: UILayoutGuide = UILayoutGuide() 
fileprivate var keyboardTopAnchorConstraint: NSLayoutConstraint! 

viewDidLoad添加keyboardAwareBottomLayoutGuide到视图,并设置相应的约束上:

self.view.addLayoutGuide(self.keyboardAwareBottomLayoutGuide) 
// this will control keyboardAwareBottomLayoutGuide.topAnchor to be so far from bottom of the bottom as is the height of the presented keyboard 
self.keyboardTopAnchorConstraint = self.view.layoutMarginsGuide.bottomAnchor.constraint(equalTo: keyboardAwareBottomLayoutGuide.topAnchor, constant: 0) 
self.keyboardTopAnchorConstraint.isActive = true 
self.keyboardAwareBottomLayoutGuide.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor).isActive = true 

然后使用以下行开始听键盘显示和隐藏:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) 
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) 

最后,使用下面的方法来控制keyboardAwareBottomLayoutGuide模仿键盘:

@objc fileprivate func keyboardWillShowNotification(notification: NSNotification) { 
    updateKeyboardAwareBottomLayoutGuide(with: notification, hiding: false) 
} 

@objc fileprivate func keyboardWillHideNotification(notification: NSNotification) { 
    updateKeyboardAwareBottomLayoutGuide(with: notification, hiding: true) 
} 

fileprivate func updateKeyboardAwareBottomLayoutGuide(with notification: NSNotification, hiding: Bool) { 
    let userInfo = notification.userInfo 

    let animationDuration = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue 
    let keyboardEndFrame = (userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue 

    let rawAnimationCurve = (userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uint32Value 

    guard let animDuration = animationDuration, 
     let keybrdEndFrame = keyboardEndFrame, 
     let rawAnimCurve = rawAnimationCurve else { 
      return 
    } 

    let convertedKeyboardEndFrame = view.convert(keybrdEndFrame, from: view.window) 

    let rawAnimCurveAdjusted = UInt(rawAnimCurve << 16) 
    let animationCurve = UIViewAnimationOptions(rawValue: rawAnimCurveAdjusted) 

    // this will move the topAnchor of the keyboardAwareBottomLayoutGuide to height of the keyboard 
    self.keyboardTopAnchorConstraint.constant = hiding ? 0 : convertedKeyboardEndFrame.size.height 

    self.view.setNeedsLayout() 

    UIView.animate(withDuration: animDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { 
     self.view.layoutIfNeeded() 
    }, completion: { success in 
     // 
    }) 
} 

现在,这一切的设置,您可以使用自动布局来约束你的意见keyboardAwareBottomLayoutGuide.topAnchor而不是self.view.layoutMarginsGuide.bottomAnchor(或self.view.bottomAnchor ,无论你使用什么)。 keyboardAwareBottomLayoutGuide会自动调整到显示或隐藏的键盘。

例子:

uiTextField.bottomAnchor.constraint(equalTo: keyboardAwareBottomLayoutGuide.topAnchor).isActive = true 

编辑:直接设置帧

虽然我强烈建议您使用自动布局,在情况下,当你无法用此去,直接设置框架可以还一个解决方案。你可以使用相同的原则。在这种方法中,你不需要布局指南,所以你不需要任何额外的实例属性。只需使用viewDidLoad来听通知登记:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) 
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) 

然后实现,将反应这些通知的方法:

@objc fileprivate func keyboardWillShowNotification(notification: NSNotification) { 
    adjustToKeyboard(with: notification, hiding: false) 
} 

@objc fileprivate func keyboardWillHideNotification(notification: NSNotification) { 
    adjustToKeyboard(with: notification, hiding: true) 
} 

fileprivate func adjustToKeyboard(with notification: NSNotification, hiding: Bool) { 
    let userInfo = notification.userInfo 

    let animationDuration = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue 
    let keyboardEndFrame = (userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue 

    let rawAnimationCurve = (userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uint32Value 

    guard let animDuration = animationDuration, 
     let keybrdEndFrame = keyboardEndFrame, 
     let rawAnimCurve = rawAnimationCurve else { 
      return 
    } 

    let convertedKeyboardEndFrame = view.convert(keybrdEndFrame, from: view.window) 

    let rawAnimCurveAdjusted = UInt(rawAnimCurve << 16) 
    let animationCurve = UIViewAnimationOptions(rawValue: rawAnimCurveAdjusted) 

    // we will go either up or down depending on whether the keyboard is being hidden or shown 
    let diffInHeight = hiding ? convertedKeyboardEndFrame.size.height : -convertedKeyboardEndFrame.size.height 

    UIView.animate(withDuration: animDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { 
     // this will move the frame of the aView according to the diffInHeight calculated above 
     // of course here you need to set all the frames that would be affected by the keyboard (this is why I prefer using autolayout) 
     self.aView?.frame = (self.aView?.frame.offsetBy(dx: 0, dy: diff))! 

     // of course, you can do anything more complex than just moving the aView up.. 
    }) 
} 

在这两种情况下,不要忘记注销观察的通知,一旦是的viewController deinitialized防止保留循环:

deinit { 
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) 
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) 
} 
+0

谢谢。即使这两种观点有不同的父母,这种工作是否会奏效 –

+0

有什么意见?我真的不知道我明白你想说什么..我的解决方案只创建一个适应键盘的人为锚点..所以不是按照左,右,上,下来布置视图,而是根据left,right,top和keyboardAwareBottomLayoutGuide.topAnchor。换句话说,通常使用自动布局,而不是使用viewController.view.bottomAnchor使用keyboardAwareBottomLayoutGuide.topAnchor。 –

+0

所以无论你想在你的视图中进行约束,你都会按照通常的方式进行操作,只需使用新的布局指南而不是静态view.bottomAnchor –