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


83

我正在使用此代码来确定键盘的大小:

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

}

我正在模拟器中运行它。

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

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


如果转换keyboardFrameBeginRect为本地坐标,则可能会有所帮助。
rmaddy14 2014年

@rmaddy并不重要,我只需要高度。
伊莱·布拉金斯基

根据方向,这可能是错误的。尽管在iOS 8下这可能不再是问题。但是请尝试一下,看看是否有所不同。
rmaddy14 2014年

@rmaddy我尝试过,但可惜它没有帮助
Eli Braginskiy 2014年

Answers:


98

使用

NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];

好答案。谢谢。您如何找到应该使用该密钥的?@souvickcse
朱利安·奥索里奥

6
CGRect keyboardFrame = [keyboardFrameBegin CGRectValue];
非常棒的2014年

12
不适用于我,键盘仍然是258,太高
marchinram

谢谢@trycatchfinally
souvickcse 2015年

1
今天学到一课。UIKeyboardFrameEndUserInfoKey和UIKeyboardFrameBeginUserInfoKey有很大的不同。谢谢@souvickcse
jejernig '17

120

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

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

  1. 苹果的系统键盘被打开(纵向)
    • 发送的UIKeyboardWillShowNotification的键盘高度为224
  2. 了Swype键盘被打开(纵向):
    • 发送的UIKeyboardWillShowNotification的键盘高度为0
    • 发送的UIKeyboardWillShowNotification的键盘高度为216
    • 发送的UIKeyboardWillShowNotification的键盘高度为256
  3. 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;
}

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

keyboardWillHide实现为reset _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标志用于视图动画方法而不是增量?
MikeR 2014年

SwiftKey(v 1.2.3)的高度为259,而iPhone6 +的iOS8.1.3为271。
Hemang 2015年

2
它仍然是可行的解决方案吗?使用SwiftKey时,我的高度是44而不是
259。– KIDdAe 2015年

疯狂,这对我有帮助,但是在显示完键盘后我需要它的高度,所以我观察一下keyboardDidShow:。为什么这些自定义键盘会触发3条通知,而Apple只会触发1条?似乎不一致。
Liron Yahdav '16

如果像我以前那样在横向模式下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)
xaphod

18

在遇到这篇StackOverflow文章之前,我也遇到了这个问题:

转换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之前,键盘rect始终处于纵向屏幕坐标。我已经添加了代码以在横向模式下手动交换高度和宽度,但是在iOS 8上中断了,iOS 8上的键盘rect方向与视图方向匹配。该convertRect溶液给出正确的结果为iOS 7或iOS 8
user1055568

7

与Swift 2.0中编写的dgangsta解决方案类似:

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以及笑脸时出现的问题
user3722523 2015年

这是酱。Swift 2.3的微小差异,但这是编译器的自动完成建议,因此没有问题。
伊桑·帕克

5

extensionUIViewController

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.
}

崔万福,请问这些意见有何用处inputContainerBottom
纳撒尼尔·布鲁默

@Nathaniel UITextField或UITextView的bottomspace约束来自bottomLayout。;)我已经在项目中对其进行了编辑。我将其重新发布
崔万福

4

有时,开发人员需要在实际显示键盘之前先知道键盘的高度,以便他们适当地预先布局界面。

如果是这种情况,请参阅以下内容:

在此处输入图片说明

这包括顶部的快速类型栏,因为在所有当前版本的iOS中默认情况下该功能处于启用状态。

如果有人需要,这是我用来测试的快速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)")
}

1

只需一个字符串即可快速:

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

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


0

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

在这种情况下,有效的方法是autocorrectionType = UITextAutocorrectionTypeNo;使用自定义键盘设置输入字段。

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


0

在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...
        }
    })

0
[notificationCenter addObserverForName:UIKeyboardWillChangeFrameNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {

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

}];
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.