Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/110.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在不显示键盘的情况下获取iOS键盘的高度_Ios_Iphone_Cocoa Touch_Keyboard - Fatal编程技术网

在不显示键盘的情况下获取iOS键盘的高度

在不显示键盘的情况下获取iOS键盘的高度,ios,iphone,cocoa-touch,keyboard,Ios,Iphone,Cocoa Touch,Keyboard,我正在尝试获取iOS键盘的高度。我已经了解并使用了订阅通知的方法,如下所述: 当用户实际显示键盘时,这种方式很好 我的问题是:我有另一个视图,我们称之为micView,它可能在键盘出现之前出现。用户可以在键入前选择使用麦克风。我希望micView的高度与键盘的高度相同,这就是为什么我需要键盘的高度,但我需要它在键盘被迫出现之前。因此,在我需要读取高度值之前,不会到达UIKeyboardWillShowNotification 我的问题是:如何通过通知或其他方法获得键盘的高度,而不让键盘出现 我

我正在尝试获取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对该问题的回答中概述的原始方法。

看起来确实停止了工作

我修改了它:

  • 添加回调以了解通知何时到达实际高度
  • 将文本字段移动到另一个窗口以避免显示,以及
  • 在模拟器中使用时设置超时,软件键盘设置为现在显示
使用Swift 4:

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