如何将底部视图移动到UIKeyboard

时间:2017-09-15 08:35:59

标签: ios

您好我正在尝试使视图的底部与UIKeyboard的顶部对齐。

更新1:如果您想尝试一下,我创建了一个github项目:https://github.com/JCzz/KeyboardProject

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

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

我可能已经看了太久了,我无法将它包裹起来: - )

你知道吗?

  1. 我如何知道UIKeyboard是否正在向下或向上?

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

  3. 我找到了以下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 个答案:

答案 0 :(得分:1)

您可以使用以下Autolayout解决方案来实现它。

首先,您需要使用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
        //
    })
}

现在设置完所有设置后,您可以使用Autolayout将视图限制为keyboardAwareBottomLayoutGuide.topAnchor,而不是self.view.layoutMarginsGuide.bottomAnchor(或self.view.bottomAnchor,无论您使用哪种方式)。 keyboardAwareBottomLayoutGuide会自动调整显示或隐藏的键盘。

示例:

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

编辑:直接设置框架

虽然我强烈建议使用Autolayout,但如果你不能使用它,直接设置框架也可以解决问题。您可以使用相同的原则。在这种方法中,您不需要布局指南,因此您不需要任何其他实例属性。只需使用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以防止保留周期,请不要忘记取消注册观察通知:

deinit {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
相关问题