ios UIKeyboardBoundsUserInfoKey 已弃用,用什么代替?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2807339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 17:13:38  来源:igfitidea点击:

UIKeyboardBoundsUserInfoKey is deprecated, what to use instead?

iosobjective-ciphoneuikeyboardiphone-sdk-3.2

提问by Mikeware

I'm working on an iPad app using 3.2 sdk. I'm dealing with obtaining the keyboard size to prevent my textfields from hidding behind it.

我正在使用 3.2 sdk 开发 iPad 应用程序。我正在处理获取键盘大小以防止我的文本字段隐藏在它后面。

I'm getting a Warning in Xcode -> UIKeyboardBoundsUserInfoKey is deprecated what should I use instead not to get this warning?

我在 Xcode 中收到警告 -> UIKeyboardBoundsUserInfoKey 已弃用 我应该使用什么来代替收到此警告?

回答by Jay

I played with the previously offered solution but still had issues. Here's what I came up with instead:

我使用了之前提供的解决方案,但仍有问题。这是我想出的:

    - (void)keyboardWillShow:(NSNotification *)aNotification {
    [self moveTextViewForKeyboard:aNotification up:YES];
}

    - (void)keyboardWillHide:(NSNotification *)aNotification {
        [self moveTextViewForKeyboard:aNotification up:NO]; 
    }

- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];

// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;

CGRect keyboardEndFrame;

[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];


[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];


// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];

CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];

newFrame.origin.y -= keyboardFrame.size.height * (up? 1 : -1);
textView.frame = newFrame;

[UIView commitAnimations];
}

回答by Alex Reynolds

From the documentationfor UIKeyboardBoundsUserInfoKey:

文档UIKeyboardBoundsUserInfoKey

The key for an NSValue object containing a CGRect that identifies the bounds rectangle of the keyboard in window coordinates. This value is sufficient for obtaining the size of the keyboard. If you want to get the origin of the keyboard on the screen (before or after animation) use the values obtained from the user info dictionary through the UIKeyboardCenterBeginUserInfoKey or UIKeyboardCenterEndUserInfoKey constants. Use the UIKeyboardFrameBeginUserInfoKey or UIKeyboardFrameEndUserInfoKey key instead.

包含 CGRect 的 NSValue 对象的键,该对象在窗口坐标中标识键盘的边界矩形。该值足以获取键盘的大小。如果要获取屏幕上键盘的原点(动画之前或之后),请使用通过 UIKeyboardCenterBeginUserInfoKey 或 UIKeyboardCenterEndUserInfoKey 常量从用户信息字典中获取的值。请改用 UIKeyboardFrameBeginUserInfoKey 或 UIKeyboardFrameEndUserInfoKey 键。

Apple recommends implementing a convenience routine such as this (which could be implemented as a category addition to UIScreen):

Apple 建议实现这样的便利例程(可以作为 的类别添加来实现UIScreen):

+ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view {
    UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window];
    return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil];
}

to recover window-adjusted keyboard frame size properties.

恢复窗口调整的键盘框架大小属性。

I took a different approach, which involves checking the device orientation:

我采用了不同的方法,包括检查设备方向:

CGRect _keyboardEndFrame;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&_keyboardEndFrame];
CGFloat _keyboardHeight = ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) ? _keyboardEndFrame.size.height : _keyboardEndFrame.size.width;

回答by iOS_User

You simply use this code:

您只需使用以下代码:

//NSVale *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
//instead of Upper line we can use either next line or nextest line.
//NSValue *aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];

回答by junjie

The following code fixes an issue in Jay's answer, which assumes that UIKeyboardWillShowNotificationwill not fire again when the keyboard is already present.

以下代码修复了Jay's answer 中的一个问题,该问题假设UIKeyboardWillShowNotification键盘已经存在时不会再次触发。

When typing with the Japanese/Chinese keyboard, iOS fires an extra UIKeyboardWillShowNotificationwith the new keyboard frame even though the keyboard is already present, leading to the height of the self.textViewbeing reduced a second time in the original code.

当使用日文/中文键盘打字时,UIKeyboardWillShowNotification即使键盘已经存在,iOS也会使用新的键盘框架触发额外的触发,导致self.textView原始代码中第二次降低高度。

This reduces self.textViewto almost nothing. It then becomes impossible to recover from this problem since we will only expect a single UIKeyboardWillHideNotificationthe next time the keyboard is dismissed.

这减少self.textView到几乎没有。然后就不可能从这个问题中恢复过来,因为UIKeyboardWillHideNotification下次键盘关闭时我们只会期待一个。

Instead of subtracting/adding height to self.textViewdepending on whether the keyboard is shown/hidden as in the original code, the following code just calculates the maximum possible height for self.textViewafter subtracting the height of the keyboard on screen.

self.textView下面的代码不是像原始代码那样根据键盘是否显示/隐藏来减去/增加高度,而是计算self.textView减去屏幕上键盘高度后的最大可能高度。

This assumes that self.textViewis suppose to fill the entire view of the view controller, and there's no other subview that needs to be visible.

这假设self.textView假设填充视图控制器的整个视图,并且没有其他需要可见的子视图。

- (void)resizeTextViewWithKeyboardNotification:(NSNotification*)notif {

    NSDictionary* userInfo = [notif userInfo];
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardFrameInWindowsCoordinates;

    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindowsCoordinates];

    [self resizeTextViewToAccommodateKeyboardFrame:keyboardFrameInWindowsCoordinates
                             withAnimationDuration:animationDuration
                                    animationCurve:animationCurve];

}

- (void)resizeTextViewToAccommodateKeyboardFrame:(CGRect)keyboardFrameInWindowsCoordinates
                           withAnimationDuration:(NSTimeInterval)duration
                                  animationCurve:(UIViewAnimationCurve)curve
{

    CGRect fullFrame = self.view.frame;

    CGRect keyboardFrameInViewCoordinates =
    [self.view convertRect:keyboardFrameInWindowsCoordinates fromView:nil];

    // Frame of the keyboard that intersects with the view. When keyboard is
    // dismissed, the keyboard frame still has width/height, although the origin
    // keeps the keyboard out of the screen.
    CGRect keyboardFrameVisibleOnScreen =
    CGRectIntersection(fullFrame, keyboardFrameInViewCoordinates);

    // Max frame availble for text view. Assign it to the full frame first
    CGRect newTextViewFrame = fullFrame;

    // Deduct the the height of any keyboard that's visible on screen from
    // the height of the text view
    newTextViewFrame.size.height -= keyboardFrameVisibleOnScreen.size.height;

    if (duration)
    {
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:duration];
        [UIView setAnimationCurve:curve];
    }

    // Adjust the size of the text view to the new one
    self.textView.frame = newTextViewFrame;

    if (duration)
    {
        [UIView commitAnimations];
    }

}

Also, don't forget to register the keyboard notifications in viewDidLoad:

另外,不要忘记在 viewDidLoad 中注册键盘通知:

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSNotificationCenter* notifCenter = [NSNotificationCenter defaultCenter];

    [notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillShowNotification object:nil];
    [notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillHideNotification object:nil];
}

About splitting the resizing code into two parts

关于将调整大小代码分成两部分

The reason why the textView resizing code is split into two parts (resizeTextViewWithKeyboardNotification:and resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:) is to fix another issue when the keyboard persists through a push from one view controller to another (see How do I detect the iOS keyboard when it stays up between controllers?).

textView 调整大小代码分为两部分 (resizeTextViewWithKeyboardNotification:resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:) 的原因是为了解决另一个问题,当键盘通过从一个视图控制器推送到另一个视图控制器时仍然存在(请参阅如何检测 iOS 键盘在控制器之间停留时?) .

Since the keyboard is already present before the view controller is pushed, there's no additional keyboard notifications being generated by iOS, and thus no way to resize the textViewbased on those keyboard notifications.

由于在推送视图控制器之前键盘已经存在,因此 iOS 不会生成额外的键盘通知,因此无法textView根据这些键盘通知调整大小。

The above code (as well as the original code) that resizes self.textViewwill thus only work when the keyboard is shown afterthe view has been loaded.

因此,上述调整大小的代码(以及原始代码)self.textView仅在视图加载显示键盘时才有效。

My solution is to create a singleton that stores the last keyboard coordinates, and on - viewDidAppear:of the viewController, call:

我的解决方案是创建一个存储最后一个键盘坐标的单例,并在- viewDidAppear:viewController 上调用:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Resize the view if there's any keyboard presence before this
    // Only call in viewDidAppear as we are unable to convertRect properly
    // before view is shown
    [self resizeViewToAccommodateKeyboardFrame:[[UASKeyboard sharedKeyboard] keyboardFrame]
                         withAnimationDuration:0
                                animationCurve:0];
}

UASKeyboardis my singleton here. Ideally we should call this in - viewWillAppear:, however in my experience (at least on iOS 6), the convertRect:fromView:method that we need to use in resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:does not properly convert the keyboard frame to the view coordinates before the view is fully visible.

UASKeyboard是我的单身人士在这里。理想情况下,我们应该在调用这个- viewWillAppear:,但是在我的经验(至少在iOS 6中),则convertRect:fromView:我们需要使用方法resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:不正确的观点之前,键盘框转换为视图坐标是完全可见。

回答by Anand Mishra

Just use the UIKeyboardFrameBeginUserInfoKeyor UIKeyboardFrameEndUserInfoKeykey instead of UIKeyboardBoundsUserInfoKey

只需使用UIKeyboardFrameBeginUserInfoKeyUIKeyboardFrameEndUserInfoKey键代替UIKeyboardBoundsUserInfoKey

回答by Cameron Lowell Palmer

- (CGSize)keyboardSize:(NSNotification *)aNotification {
    NSDictionary *info = [aNotification userInfo];
    NSValue *beginValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];

    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

    CGSize keyboardSize;
    if ([UIKeyboardDidShowNotification isEqualToString:[aNotification name]]) {
        _screenOrientation = orientation;
        if (UIDeviceOrientationIsPortrait(orientation)) {
            keyboardSize = [beginValue CGRectValue].size;
        } else {
            keyboardSize.height = [beginValue CGRectValue].size.width;
            keyboardSize.width = [beginValue CGRectValue].size.height;
        }
    } else if ([UIKeyboardDidHideNotification isEqualToString:[aNotification name]]) {
        // We didn't rotate
        if (_screenOrientation == orientation) {
            if (UIDeviceOrientationIsPortrait(orientation)) {
                keyboardSize = [beginValue CGRectValue].size;
            } else {
                keyboardSize.height = [beginValue CGRectValue].size.width;
                keyboardSize.width = [beginValue CGRectValue].size.height;
            }
        // We rotated
        } else if (UIDeviceOrientationIsPortrait(orientation)) {
            keyboardSize.height = [beginValue CGRectValue].size.width;
            keyboardSize.width = [beginValue CGRectValue].size.height;
        } else {
            keyboardSize = [beginValue CGRectValue].size;
        }
    }


    return keyboardSize;
}

回答by Thomas

@Jason, you code if fine except for one point.

@Jason,除了一点之外,如果没问题,您可以编写代码。

At the moment you are not actually animating anything and the view will simply `pop' to its new size.height.

目前你实际上并没有动画任何东西,视图将简单地“弹出”到它的新 size.height。

You have to specify a state from which to animate. An animation is a sort of (from state)->(to state) thing.

你必须指定一个国家从中动画。动画是一种(从状态)->(到状态)的东西。

Luckily there is a very convenient method to specify the current state of the view as the (from state).

幸运的是,有一种非常方便的方法可以将视图的当前状态指定为 (from state)。

[UIView setAnimationBeginsFromCurrentState:YES];

If you add that line right after beginAnimations:context: your code works perfectly.

如果您在 beginAnimations:context: 之后立即添加该行:您的代码可以完美运行。

回答by Mohammed Abunada

Its worked like this

它是这样工作的

This is the constraint of the save button bottom

这是保存按钮底部的约束

@IBOutlet weak var saveBtnBottom: NSLayoutConstraint!
@IBOutlet weak var nameText: UITextField!

Inside viewDidLoad

内部视图DidLoad

NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
nameText.delegate = self

This is the functions we need

这是我们需要的功能

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    nameText.resignFirstResponder()
    return true
}


@objc func keyBoardWillShow(notification: Notification){
    if let userInfo = notification.userInfo as? Dictionary<String, AnyObject>{
        let frame = userInfo[UIResponder.keyboardFrameEndUserInfoKey]
        let keyBoardRect = frame?.cgRectValue
        if let keyBoardHeight = keyBoardRect?.height {
            self.saveBtnBottom.constant = keyBoardHeight 

            UIView.animate(withDuration: 0.5, animations: {
                self.view.layoutIfNeeded()
            })
        }
    }
}

@objc func keyBoardWillHide(notification: Notification){
    self.saveBtnBottom.constant = 30.0
    UIView.animate(withDuration: 0.5, animations: {
        self.view.layoutIfNeeded()
    })
}