在不显示键盘的情况下获取iOS键盘的高度
我正在尝试获取iOS键盘的高度。我已经了解并使用了订阅通知的方法,如下所述: 当用户实际显示键盘时,这种方式很好 我的问题是:我有另一个视图,我们称之为micView,它可能在键盘出现之前出现。用户可以在键入前选择使用麦克风。我希望micView的高度与键盘的高度相同,这就是为什么我需要键盘的高度,但我需要它在键盘被迫出现之前。因此,在我需要读取高度值之前,不会到达UIKeyboardWillShowNotification 我的问题是:如何通过通知或其他方法获得键盘的高度,而不让键盘出现在不显示键盘的情况下获取iOS键盘的高度,ios,iphone,cocoa-touch,keyboard,Ios,Iphone,Cocoa Touch,Keyboard,我正在尝试获取iOS键盘的高度。我已经了解并使用了订阅通知的方法,如下所述: 当用户实际显示键盘时,这种方式很好 我的问题是:我有另一个视图,我们称之为micView,它可能在键盘出现之前出现。用户可以在键入前选择使用麦克风。我希望micView的高度与键盘的高度相同,这就是为什么我需要键盘的高度,但我需要它在键盘被迫出现之前。因此,在我需要读取高度值之前,不会到达UIKeyboardWillShowNotification 我的问题是:如何通过通知或其他方法获得键盘的高度,而不让键盘出现 我
我考虑过显式地强制键盘出现在viewDidLoad中,这样我就可以将一个实例变量设置为该值,然后隐藏它,并消除这两种情况下的动画。但这真的是唯一的方法吗 您可以使用的一种快速解决方案,与您希望缓存键盘时使用的解决方案相同(第一次显示键盘时,会有轻微延迟…)。图书馆在建。有趣的是:
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:field];
[field becomeFirstResponder];
[field resignFirstResponder];
[field removeFromSuperview];
所以基本上是先展示,然后隐藏。您可以监听通知,只需获取高度,而不必实际看到它奖金:您可以缓存它。:) 这个Swift类提供了一个交钥匙解决方案,可以管理所有必要的通知和初始化,让您只需调用类方法并返回键盘大小或高度 从Swift呼叫:
let keyboardHeight = KeyboardService.keyboardHeight()
let keyboardSize = KeyboardService.keyboardSize()
从Objective-C呼叫:
CGFloat keyboardHeight = [KeyboardService keyboardHeight];
CGRect keyboardSize = [KeyboardService keyboardSize];
如果要将其用于初始视图布局,请从类的viewwillappease
方法调用此函数,在该类中,您希望在键盘出现之前输入键盘高度或大小。不应在viewDidLoad中调用它,因为正确的值取决于视图的布局。然后,您可以使用键盘服务返回的值设置autolayout约束常量,或者以其他方式使用该值。例如,您可能希望在prepareforsgue
中获取键盘高度,以帮助设置与通过嵌入序列填充的containerView内容相关联的值
注意安全区域、键盘高度和iPhone X:键盘高度的值返回键盘的全高,在iPhone X上,键盘的全高延伸到屏幕本身的边缘,而不仅仅是安全区域的插图。因此,如果使用返回值设置自动布局约束值,则应将该约束附加到superview底部边缘,而不是安全区域 注意模拟器中的硬件键盘:
连接硬件键盘时,此代码将提供该硬件键盘的屏幕高度,即无高度。当然,这种状态确实需要考虑,因为这模拟了如果将硬件键盘连接到实际设备上会发生什么情况。因此,预期键盘高度的布局需要适当响应零的键盘高度 键盘服务类别:
通常,如果从Objective-C调用,只需在Objective-C类中导入应用程序的Swift桥接头
MyApp Swift.h
import UIKit
class KeyboardService: NSObject {
static var serviceSingleton = KeyboardService()
var measuredSize: CGRect = CGRect.zero
@objc class func keyboardHeight() -> CGFloat {
let keyboardSize = KeyboardService.keyboardSize()
return keyboardSize.size.height
}
@objc class func keyboardSize() -> CGRect {
return serviceSingleton.measuredSize
}
private func observeKeyboardNotifications() {
let center = NotificationCenter.default
center.addObserver(self, selector: #selector(self.keyboardChange), name: .UIKeyboardDidShow, object: nil)
}
private func observeKeyboard() {
let field = UITextField()
UIApplication.shared.windows.first?.addSubview(field)
field.becomeFirstResponder()
field.resignFirstResponder()
field.removeFromSuperview()
}
@objc private func keyboardChange(_ notification: Notification) {
guard measuredSize == CGRect.zero, let info = notification.userInfo,
let value = info[UIKeyboardFrameEndUserInfoKey] as? NSValue
else { return }
measuredSize = value.cgRectValue
}
override init() {
super.init()
observeKeyboardNotifications()
observeKeyboard()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
点头:这里的observeKeyboard方法基于佩雷斯在Objective-C对该问题的回答中概述的原始方法。看起来确实停止了工作 我修改了它:
- 添加回调以了解通知何时到达实际高度
- 将文本字段移动到另一个窗口以避免显示,以及
- 在模拟器中使用时设置超时,软件键盘设置为现在显示
import UIKit
public class KeyboardSize {
private static var sharedInstance: KeyboardSize?
private static var measuredSize: CGRect = CGRect.zero
private var addedWindow: UIWindow
private var textfield = UITextField()
private var keyboardHeightKnownCallback: () -> Void = {}
private var simulatorTimeout: Timer?
public class func setup(_ callback: @escaping () -> Void) {
guard measuredSize == CGRect.zero, sharedInstance == nil else {
return
}
sharedInstance = KeyboardSize()
sharedInstance?.keyboardHeightKnownCallback = callback
}
private init() {
addedWindow = UIWindow(frame: UIScreen.main.bounds)
addedWindow.rootViewController = UIViewController()
addedWindow.addSubview(textfield)
observeKeyboardNotifications()
observeKeyboard()
}
public class func height() -> CGFloat {
return measuredSize.height
}
private func observeKeyboardNotifications() {
let center = NotificationCenter.default
center.addObserver(self, selector: #selector(self.keyboardChange), name: UIResponder.keyboardDidShowNotification, object: nil)
}
private func observeKeyboard() {
let currentWindow = UIApplication.shared.keyWindow
addedWindow.makeKeyAndVisible()
textfield.becomeFirstResponder()
currentWindow?.makeKeyAndVisible()
setupTimeoutForSimulator()
}
@objc private func keyboardChange(_ notification: Notification) {
textfield.resignFirstResponder()
textfield.removeFromSuperview()
guard KeyboardSize.measuredSize == CGRect.zero, let info = notification.userInfo,
let value = info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue
else { return }
saveKeyboardSize(value.cgRectValue)
}
private func saveKeyboardSize(_ size: CGRect) {
cancelSimulatorTimeout()
KeyboardSize.measuredSize = size
keyboardHeightKnownCallback()
KeyboardSize.sharedInstance = nil
}
private func setupTimeoutForSimulator() {
#if targetEnvironment(simulator)
let timeout = 2.0
simulatorTimeout = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false, block: { (_) in
print(" KeyboardSize")
print(" .keyboardDidShowNotification did not arrive after \(timeout) seconds.")
print(" Please check \"Toogle Software Keyboard\" on the simulator (or press cmd+k in the simulator) and relauch your app.")
print(" A keyboard height of 0 will be used by default.")
self.saveKeyboardSize(CGRect.zero)
})
#endif
}
private func cancelSimulatorTimeout() {
simulatorTimeout?.invalidate()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
按以下方式使用:
let splashVC = some VC to show in the key window during the app setup (just after the didFinishLaunching with options)
window.rootViewController = splashVC
KeyboardSize.setup() { [unowned self] in
let kbHeight = KeyboardSize.height() // != 0 :)
// continue loading another things or presenting the onboarding or the auth
}
对于iOS 14.0,我注意到在大约第10次呼叫时停止工作,因为
NotificationCenter
停止广播keyboardChange
通知。我无法完全理解为什么会发生这种情况
因此,我调整了解决方案,使KeyboardSize
成为单例,并添加了一个方法updateKeyboardHeight()
:
static let shared = KeyboardSize()
/**
Height of keyboard after the class is initialized
*/
private(set) var keyboardHeight: CGFloat = 0.0
private override init() {
super.init()
observeKeyboardNotifications()
observeKeyboard()
}
func updateKeyboardHeight() {
observeKeyboardNotifications()
observeKeyboard()
}
并将其用作
KeyboardSize.shared.updateKeyboardHeight()
let heightOfKeyboard = KeyboardSize.shared.keyboardHeight
非常感谢。这很有效。在设置通知选择器之后,我将代码放在viewwillappearch方法中,它就可以工作了。我想投票,但我还没有这个特权。为了澄清问题,您知道键盘缓存是否仍然是具有更好内部结构的新iOS设备上的一个主要问题吗。我现在在应用商店的iOS 8.0版应用程序上可以看到它。field的值应该是多少?@John field将是一个
UITextField
。上次我使用这种方法,它工作正常,但现在只有在用户先打开任何键盘后,键盘高度才会返回,发生了什么事?谢谢,为我效劳
KeyboardSize.shared.updateKeyboardHeight()
let heightOfKeyboard = KeyboardSize.shared.keyboardHeight