不推荐使用UIKeyboardBoundsUserInfoKey,而是使用什么?

时间:2010-05-11 00:28:15

标签: ios objective-c iphone uikeyboard iphone-sdk-3.2

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

我在Xcode中收到警告 - >不推荐使用UIKeyboardBoundsUserInfoKey,而不是获取此警告?

9 个答案:

答案 0 :(得分:87)

我使用之前提供的解决方案,但仍有问题。以下是我提出的内容:

    - (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];
}

答案 1 :(得分:55)

来自UIKeyboardBoundsUserInfoKey的{​​{3}}:

  

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

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];
}

恢复窗口调整的键盘框架尺寸属性。

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

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

答案 2 :(得分:9)

您只需使用此代码:

//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];

答案 3 :(得分:3)

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

使用日文/中文键盘输入时,即使键盘已经存在,iOS也会使用新的键盘框架激发额外的UIKeyboardWillShowNotification,从而导致self.textView的高度再次降低在原始代码中。

这会将self.textView减少到几乎为零。然后就不可能从这个问题中恢复,因为下次键盘被解雇时我们只会期待一个UIKeyboardWillHideNotification

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

这假设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];
    }

}

另外,不要忘记在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];
}

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

将textView大小调整代码分为两部分(resizeTextViewWithKeyboardNotification:resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:)的原因是,当键盘从一个视图控制器推送到另一个视图控制器时,会解决另一个问题(请参阅{{ 3}})。

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

调整self.textView大小的上述代码(以及原始代码)仅在键盘显示 >视图加载后才会起作用。

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

- (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];
}

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

答案 4 :(得分:2)

只需使用UIKeyboardFrameBeginUserInfoKeyUIKeyboardFrameEndUserInfoKey密钥而不是UIKeyboardBoundsUserInfoKey

答案 5 :(得分:1)

@Jason,除非有一点,否则你的代码很好。

目前你实际上并没有动画任何东西,视图只会“弹出”到它的新尺寸。高度。

您必须指定动画的状态。动画是一种(从状态) - >(到状态)的东西。

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

[UIView setAnimationBeginsFromCurrentState:YES];

如果你在beginAnimations:context之后添加该行:你的代码完美无缺。

答案 6 :(得分:1)

- (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;
}

答案 7 :(得分:0)

答案 8 :(得分:0)

它是这样工作的

这是“保存”按钮底部的约束

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

内部viewDidLoad

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

这是我们需要的功能

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()
    })
}