我正在使用3.2 sdk开发iPad应用程序。我正在处理获取键盘大小以防止我的文本字段隐藏在它后面。
我在Xcode中收到警告 - >不推荐使用UIKeyboardBoundsUserInfoKey,而不是获取此警告?
答案 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)
只需使用UIKeyboardFrameBeginUserInfoKey
或UIKeyboardFrameEndUserInfoKey
密钥而不是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()
})
}