簡體   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