ios - 如何将底部 View 移动到 UIKeyboard 的顶部

标签 ios

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

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

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

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

我可能已经看这个太久了,我无法全神贯注:-)

你知道怎么做吗?

  1. 我如何知道 UIKeyboard 是在下降还是上升的过程中?

  2. 如果 UIKeyboard 启动,那么如何将它与 View 对齐(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{

        }

    }
}

最佳答案

您可以使用以下自动布局解决方案实现它。

首先,您需要 UILayoutGuide 来模拟键盘感知底部 anchor ,以及 NSLayoutConstraint 来控制此布局指南:

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

viewDidLoad 中,将 keyboardAwareBottomLayoutGuide 添加到 View 并设置适当的约束:

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 将 View 限制为 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)

然后实现对这些通知使用react的方法:

@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)
}

关于ios - 如何将底部 View 移动到 UIKeyboard 的顶部,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46235188/

相关文章:

ios - 将 "iCloud"权限添加到您的应用程序 ID

php - 尝试让 php 使用完整的 url 而不是相对路径输出 xml

ios - 使用大标题时,不会触发 UIScrollView 中的 UIRefreshControl

ios - 没有为 UITableViewCell 对象调用 awakeFromNib

ios - 重新启动时始终显示特定 View

iOS7 Safari : tapping on fixed positioned header bar with higher z-index triggers event handler of the element underneathe it

ios - 子类的类上的泛型

ios - 我无法使用 Swift 4.0 使用 Spotify iOS SDK 播放音乐

ios - 在 Swift map 上的 MKOverlay 中添加模糊 View

ios - 如何制作水平滚动但垂直固定的单行 Collection View ?