繁体   English   中英

iOS-位置视图设置了距屏幕或键盘底部(如果正在显示)的距离,而无需订阅键盘通知

[英]iOS - position view set distance from bottom of screen or keyboard (if it is showing) without subscribing to keyboard notifications

在Android中,您可以使用RelativeLayout并使用layout_alignParentBottom将视图(例如按钮)固定到其底部。 当键盘出现时,视图将在其上方。

有没有一种方法可以在iOS中做到这一点, 而无需订阅键盘事件并根据键盘高度调整视图的约束?

我问是因为我看到的所有示例都订阅了键盘事件。 但这从我的经验来看是相当错误的。 您不仅必须订阅键盘事件,还必须订阅应用程序范围的事件。

编辑:为澄清起见,我正在询问我到底在做什么。 没有添加inputAccessoryView 我希望视图(无论是按钮,图像还是其他)始终与屏幕底部保持固定的距离。 当键盘出现时,我希望该视图与键盘顶部的距离相同。 如果键盘消失,则视图将向下移动到其原始位置。

目前没有其他方法。 显示键盘是应用程序范围内的事件,因此设计使然。 您可以获取有关框架更改的通知,然后在需要时相应地布置视图。 有一些工具可以为您提供帮助,例如提到的IQKeyboard,但请注意,此工具在多个iOS版本和/或设备上可能确实存在错误,因此您需要不断更新该库。 它也非常hackhack,但确实不需要很多工作。

通过键盘通知,您可以使用高级工具来简化操作。 我前一段时间使用的是:

import UIKit

protocol KeyboardManagerDidChangeVisibleDelegate: class {
    func keyboardManagerChangedKeyboardVisible(sender: KeyboardManager, visible: Bool)
}
protocol KeyboardManagerWillChangeFrameDelegate: class {
    func keyboardManagerWillChangeKeyboardFrame(sender: KeyboardManager, from startFrame: CGRect, to endFrame: CGRect)
}
protocol KeyboardManagerDidChangeFrameDelegate: class {
    func keyboardManagerDidChangeKeyboardFrame(sender: KeyboardManager, from startFrame: CGRect, to endFrame: CGRect)
}

class KeyboardManager {

    var keyboardVisible: Bool = false
    var keyboardFrame: CGRect = CGRect.zero

    var visibilityDelegate: KeyboardManagerDidChangeVisibleDelegate?
    var willChangeFrameDelegate: KeyboardManagerWillChangeFrameDelegate?
    var didChangeFrameDelegate: KeyboardManagerDidChangeFrameDelegate?

    static var sharedInstance: KeyboardManager = {
        let manager = KeyboardManager(isShared: true)
        return manager
    }()

    deinit {
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillChangeFrame, object: nil)
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
    }

    convenience init() {
        self.init(isShared: false)

    }

    private init(isShared: Bool) {
        attachNotifications()

        if isShared == false {
            keyboardVisible = KeyboardManager.sharedInstance.keyboardVisible
            keyboardFrame = KeyboardManager.sharedInstance.keyboardFrame
        }
    }

    private func attachNotifications() {

        NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardChange), name: .UIKeyboardWillChangeFrame, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillShow), name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillHide), name: .UIKeyboardWillHide, object: nil)

    }

    @objc private func onKeyboardChange(notification: NSNotification) {
        guard let info = notification.userInfo else {
            return
        }
        guard let value: NSValue = info[UIKeyboardFrameEndUserInfoKey] as? NSValue else {
            return
        }
        guard let oldValue: NSValue = info[UIKeyboardFrameBeginUserInfoKey] as? NSValue else {
            return
        }

        let newFrame = value.cgRectValue
        self.keyboardFrame = newFrame

        let oldFrame = oldValue.cgRectValue

        if let durationNumber = info[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, let keyboardCurveNumber = info[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber {
            let duration = durationNumber.doubleValue
            let keyboardCurve = keyboardCurveNumber.intValue
            let curve: UIViewAnimationCurve = UIViewAnimationCurve(rawValue: keyboardCurve) ?? .linear
            let options = UIViewAnimationOptions(rawValue: UInt(curve.rawValue << 16))

            UIView.animate(withDuration: duration, delay: 0, options: options, animations: {
                self.willChangeFrameDelegate?.keyboardManagerWillChangeKeyboardFrame(sender: self, from: oldFrame, to: newFrame)
            }, completion: { _ in
                self.didChangeFrameDelegate?.keyboardManagerDidChangeKeyboardFrame(sender: self, from: oldFrame, to: newFrame)
            })
        } else {
            self.willChangeFrameDelegate?.keyboardManagerWillChangeKeyboardFrame(sender: self, from: oldFrame, to: newFrame)
            self.didChangeFrameDelegate?.keyboardManagerDidChangeKeyboardFrame(sender: self, from: oldFrame, to: newFrame)
        }
    }
    @objc private func onKeyboardWillShow(notification: NSNotification) {
        self.keyboardVisible = true
        self.visibilityDelegate?.keyboardManagerChangedKeyboardVisible(sender: self, visible: self.keyboardVisible)
    }
    @objc private func onKeyboardWillHide(notification: NSNotification) {
        self.keyboardVisible = false
        self.visibilityDelegate?.keyboardManagerChangedKeyboardVisible(sender: self, visible: self.keyboardVisible)
    }

}

我在这里所做的订阅将出现委托KeyboardManager.sharedInstance.willChangeFrameDelegate = self in view将出现在视图控制器的方法中。 那么实现就是:

extension MyViewController: KeyboardManagerWillChangeFrameDelegate {

    func keyboardManagerWillChangeKeyboardFrame(sender: KeyboardManager, from startFrame: CGRect, to endFrame: CGRect) {
        panelBottomConstraint?.constant = view.bounds.height-max(0, view.convert(endFrame, from: nil).origin.y)
    }

}

因此仍然使用约束,但是由于管理器仅导入一次,因此使用时的代码量相对较小。 这应该已经为您的视图以及键盘动画了,这很好。

至于越野车,这个过程从来没有让我失败,但是总的来说,在iOS中使用键盘总是很痛苦,而且很容易产生错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM