在 iOS8 中无法获得正确的键盘高度值

Posted

技术标签:

【中文标题】在 iOS8 中无法获得正确的键盘高度值【英文标题】:can't get correct value of keyboard height in iOS8 【发布时间】:2014-11-10 13:39:40 【问题描述】:

我使用这段代码来确定键盘的大小:

- (void)keyboardWillChange:(NSNotification *)notification 
    NSDictionary* keyboardInfo = [notification userInfo];
    NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
    CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];


我正在模拟器中运行它。

问题是因为 ios 8 这不会给出正确的值,如果键盘建议是向上的或者如果我按下它们我会得到不同的(不正确的)值。

如何获得包括键盘建议在内的键盘的确切尺寸?

【问题讨论】:

keyboardFrameBeginRect 转换为本地坐标可能会有所帮助。 @rmaddy 没关系,我只需要身高。 这可能是错误的,具体取决于方向。尽管在 iOS 8 下这可能不再是问题。但请尝试一下,看看它是否有所作为。 @rmaddy 我试过了,可惜没用 【参考方案1】:

使用

NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];

【讨论】:

很好的答案。谢谢。您是如何发现应该使用该密钥的? @souvickcse CGRect keyboardFrame = [keyboardFrameBegin CGRectValue]; 对我不起作用,键盘还是 258,太高了 在iPhone横屏模式下,我发现在iOS 10(普通键盘)上必须使用UIKeyboardFrameBeginUserInfoKey,否则原点报错。 今天吸取了教训。 UIKeyboardFrameEndUserInfoKey 和 UIKeyboardFrameBeginUserInfoKey 有很大区别。谢谢@souvickcse【参考方案2】:

随着 iOS 中自定义键盘的引入,这个问题变得有点复杂。

简而言之,UIKeyboardWillShowNotification 可以被自定义键盘实现多次调用:

    Apple 系统键盘打开时(纵向) UIKeyboardWillShowNotification 的键盘高度为 224 Swype 键盘 打开时(纵向): UIKeyboardWillShowNotification 以 0 的键盘高度发送 UIKeyboardWillShowNotification 以 216 的键盘高度发送 UIKeyboardWillShowNotification 的键盘高度为 256 SwiftKey 键盘 打开时(纵向): UIKeyboardWillShowNotification 以 0 的键盘高度发送 UIKeyboardWillShowNotification 以 216 的键盘高度发送 UIKeyboardWillShowNotification 的键盘高度为 259

为了在一个代码行中正确处理这些场景,您需要:

针对 UIKeyboardWillShowNotificationUIKeyboardWillHideNotification 通知注册观察者:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];    
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];

创建一个全局变量来跟踪当前键盘高度:

CGFloat _currentKeyboardHeight = 0.0f;

实现 keyboardWillShow 以响应当前键盘高度的变化:

- (void)keyboardWillShow:(NSNotification*)notification 
   NSDictionary *info = [notification userInfo];
   CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
   CGFloat deltaHeight = kbSize.height - _currentKeyboardHeight; 
   // Write code to adjust views accordingly using deltaHeight
   _currentKeyboardHeight = kbSize.height;

注意:您可能希望为视图的偏移设置动画。 info 字典包含一个由 UIKeyboardAnimationDurationUserInfoKey 键入的值。此值可用于以与显示键盘相同的速度为您的更改设置动画。

实现 keyboardWillHide 以重置 _currentKeyboardHeight 并对被关闭的键盘做出反应:

- (void)keyboardWillHide:(NSNotification*)notification 
   NSDictionary *info = [notification userInfo];
   CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
   // Write code to adjust views accordingly using kbSize.height
   _currentKeyboardHeight = 0.0f;

【讨论】:

dgangsta,你的研究很有趣,但问题的问题只是获取 FrameBegin 而不是 FrameEnd 属性。根据您的回答,您是否考虑过使用 UIViewAnimationOptionBeginFromCurrentState 标志来查看动画方法而不是增量? SwiftKey(v 1.2.3) 高度为 259,我在 iOS8.1.3 的 iPhone6+ 中得到 271。 它仍然是一个有效的解决方案吗?使用 SwiftKey 时,我得到的高度是 44 而不是 259。 疯了,这对我有帮助,但我需要它已经显示后的键盘高度,所以我观察了 keyboardDidShow: 。为什么这些自定义键盘会触发 3 个通知,而 Apple 只会触发一个?似乎不一致。 如果您像我一样在横向模式下遇到 iPhone 的问题,那是因为框架 END 键的来源错误(至少对于普通的 iOS 10 键盘而言)。 KEYBOARD BEGIN RECT: (0.0, 375.0, 667.0, 162.0) ... KEYBOARD END RECT: (0.0, 213.0, 667.0, 162.0)【参考方案3】:

我也遇到过这个问题,直到我看到这篇 *** 文章:

Convert UIKeyboardFrameEndUserInfoKey

这将向您展示如何使用convertRect 函数将键盘的大小转换为可用的大小,但在屏幕方向上。

NSDictionary* d = [notification userInfo];
CGRect r = [d[UIKeyboardFrameEndUserInfoKey] CGRectValue];
r = [myView convertRect:r fromView:nil];

以前,我有一个 iPad 应用程序,它使用 UIKeyboardFrameEndUserInfoKey,但没有使用 convertRect,它运行良好。

但在 iOS 8 中,它不再正常工作。突然,它会报告我的键盘在 iPad 上以横向模式运行,1024 像素高

所以现在,在 iOS 8 中,您必须使用这个 convertRect 函数。

【讨论】:

iOS8 之前的键盘矩形始终是纵向屏幕坐标。我添加了代码以在横向模式下手动交换高度和宽度,但这在 iOS 8 上中断了。键盘矩形方向与视图方向匹配。 convertRect 解决方案为 iOS 7 或 iOS 8 提供了正确的结果。【参考方案4】:

类似dgangsta's Swift 2.0 编写的解决方案:

override func viewDidLoad() 
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)


deinit 
    NSNotificationCenter.defaultCenter().removeObserver(self)


func keyboardWillShow(notification: NSNotification) 
    guard let kbSizeValue = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else  return 
    guard let kbDurationNumber = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber else  return 
    animateToKeyboardHeight(kbSizeValue.CGRectValue().height, duration: kbDurationNumber.doubleValue)


func keyboardWillHide(notification: NSNotification) 
    guard let kbDurationNumber = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber else  return 
    animateToKeyboardHeight(0, duration: kbDurationNumber.doubleValue)


func animateToKeyboardHeight(kbHeight: CGFloat, duration: Double) 
    // your custom code here

【讨论】:

显示/隐藏 quickType 以及笑脸时出现问题 这是酱汁。 Swift 2.3 中的细微差别,但它是编译器的自动完成建议,所以没有问题。【参考方案5】:

我为UIViewController制作extension

extension UIViewController 
    func keyboardWillChangeFrameNotification(notification: NSNotification, scrollBottomConstant: NSLayoutConstraint) 
        let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
        let curve = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber
        let keyboardBeginFrame = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
        let keyboardEndFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()

        let screenHeight = UIScreen.mainScreen().bounds.height
        let isBeginOrEnd = keyboardBeginFrame.origin.y == screenHeight || keyboardEndFrame.origin.y == screenHeight
        let heightOffset = keyboardBeginFrame.origin.y - keyboardEndFrame.origin.y - (isBeginOrEnd ? bottomLayoutGuide.length : 0)

        UIView.animateWithDuration(duration.doubleValue,
            delay: 0,
            options: UIViewAnimationOptions(rawValue: UInt(curve.integerValue << 16)),
            animations:  () in
                scrollBottomConstant.constant = scrollBottomConstant.constant + heightOffset
                self.view.layoutIfNeeded()
            ,
            completion: nil
        )
    

你可以这样使用:

override func viewDidLoad() 
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChangeFrameNotification:", name: UIKeyboardWillChangeFrameNotification, object: nil)


...

deinit 
    NSNotificationCenter.defaultCenter().removeObserver(self)


func keyboardWillChangeFrameNotification(notification: NSNotification) 
    self.keyboardWillChangeFrameNotification(notification, scrollBottomConstant: inputContainerBottom)
    // Write more to here if you want.

【讨论】:

Wanbok Choi,inputContainerBottom 使用的视图是什么? @Nathaniel UITextField 或 UITextView 的底部空间限制来自 bottomLayout。 ;) 我在我的项目中编辑了它。我会转发的【参考方案6】:

我注意到在默认键盘和自定义 (UIPickerView) 键盘之间切换时显示的问题 - 从默认键盘切换后,自定义键盘将显示 253 高度而不是 162。

在这种情况下起作用的是使用自定义键盘为输入字段设置autocorrectionType = UITextAutocorrectionTypeNo;

该问题仅在 iOS 8 中出现(仅在模拟器上测试)。它不会出现在 iOS 9(模拟器或设备)中。

【讨论】:

【参考方案7】:

swift只有一个字符串:

let keyboardSize = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size

UIKeyboardFrameEndUserInfoKey 始终存储NSValue,因此无需检查。

【讨论】:

【参考方案8】:

在 Swift 中,不是一行...

self.keyboardDidShowObserver = NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardDidShowNotification, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock:  (notification) in
        if let userInfo = notification.userInfo, let keyboardFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue 
            let keyboardRect = keyboardFrameValue.CGRectValue()
            // keyboardRect.height gives the height of the keyboard
            // your additional code here...
        
    )

【讨论】:

【参考方案9】:
[notificationCenter addObserverForName:UIKeyboardWillChangeFrameNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) 

    float keyboardHeight = [[note.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;

];

【讨论】:

【参考方案10】:

有时,开发人员需要在键盘实际显示之前知道它的高度,从而允许他们对界面进行适当的预布局。

如果是这样,这里有一个包容性规范:

这包括顶部的快速输入栏,因为它在所有当前版本的 iOS 中默认启用。

这是我用来测试的 swift 3 通知设置,如果有人需要的话:

override func viewDidLoad() 
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)


func keyboardWillShow(notification: NSNotification) 
    guard let keyboardSize = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else  return 
    print("\(keyboardSize)")

【讨论】:

以上是关于在 iOS8 中无法获得正确的键盘高度值的主要内容,如果未能解决你的问题,请参考以下文章

如何获得 iOS 8.3 表情符号键盘高度?

iOS 8 自定义键盘:更改高度而不发出警告“无法同时满足约束...”

无法获得 wkWebView 的正确高度?

Swift:在 sizetofit 之后无法获得标题单元格标签的正确高度

iOS 8自定义键盘:更改高度

如何在 iOS 中计算键盘高度?