与此问题类似:iPad: Detecting External Keyboard,我正在开发一个iPad应用程序,该应用程序使用带有自定义inputAccessoryView
的文本字段来为虚拟键盘提供其他功能。
但是,如果硬件键盘(例如蓝牙键盘)连接到设备,则软件键盘未按预期显示,但由于某种原因,inputAccessoryView 仍然可见在屏幕的底部。此外,这似乎导致触发UIKeyboardDidShowNotification
(因此,即使硬件键盘用于输入,也可以移动我的视图以避免键盘实际上不存在遮挡)。
我找到了几种解决方案来检测硬件键盘是否已连接,但是所有这些都在接收到UIKeyboardDidShowNotification
后检查状态,此时inputAccessoryView已经可见(例如{ {3}})。
如果没有连接硬件键盘,我正在寻找一种只显示inputAccessoryView的方法。因此,我需要知道是否连接了硬件键盘之前 UIKeyboardDidShowNotification
被触发。
此处提供的已接受解决方案How can I detect if an external keyboard is present on an iPad?对我来说无处可选,因为他们使用的私有API可能导致我的应用被拒绝。
答案 0 :(得分:4)
这只是@arlomedia对答案的增强。我所做的是关注willShow和didShow。
我使用的willShow将我的textview移动到位,使其以与键盘相同的速度移动。
我使用上述技术检查键盘表观大小的didShow,并相应地隐藏/显示accessoryInputView。
非常重要我还默认将该视图设置为隐藏,并且当收到一个willHide事件时,它会再次被隐藏。
- (void) addKeyboardObserver {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHidden:) name:UIKeyboardWillHideNotification object:nil];
}
- (void) removeKeyboardObserver {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification*)notification {
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// If we're on iOS7 or earlier and landscape then the height is in the
// width.
//
if ((IS_LANDSCAPE == YES) && (IS_IOS8_OR_LATER == NO)) {
keyboardSize.height = keyboardSize.width;
}
NSNumber *rate = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey];
CGRect textFieldFrame = self.textField.frame;
textFieldFrame.origin.y = ([Util screenHeight] - keyboardSize.height) - textFieldFrame.size.height - [Util scaledHeight:10.0];
// Move the text field into place.
//
[UIView animateWithDuration:rate.floatValue animations:^{
self.answerTextField.frame = textFieldFrame;
}];
keyboardShown = YES;
}
- (void)keyboardDidShow:(NSNotification*)notification {
CGRect keyboardBeginFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGSize keyboardSize = keyboardBeginFrame.size;
// If we're on iOS7 or earlier and landscape then the height is in the
// width.
//
if ((IS_LANDSCAPE == YES) && (IS_IOS8_OR_LATER == NO)) {
keyboardSize.height = ABS(keyboardBeginFrame.origin.x - keyboardEndFrame.origin.x); // the keyboard will move by an amount equal to its height when it appears; ABS is needed for upside-down orientations
} else {
keyboardSize.height = ABS(keyboardBeginFrame.origin.y - keyboardEndFrame.origin.y); // the keyboard will move by an amount equal to its height when it appears; ABS is needed for upside-down orientations
}
NSNumber *rate = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey];
[UIView animateWithDuration:rate.floatValue animations:^{
if (keyboardSize.height <= self.accessoryBar.frame.size.height) {
self.textField.inputAccessoryView.hidden = YES;
self.answerTextField.inputAccessoryView.userInteractionEnabled = NO;
} else {
self.textField.inputAccessoryView.hidden = NO;
self.answerTextField.inputAccessoryView.userInteractionEnabled = YES;
}
}];
keyboardShown = YES;
}
- (void)keyboardHidden:(NSNotification*)notification {
NSNumber *rate = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey];
// Remove/hide the accessory view so that next time the text field gets focus, if a hardware
// keyboard is used, the accessory bar is not shown.
//
[UIView animateWithDuration:rate.floatValue animations:^{
self.textField.inputAccessoryView.hidden = YES;
self.answerTextField.inputAccessoryView.userInteractionEnabled = NO;
}];
keyboardShown = NO;
}
注意已修改为userInteractionEnabled添加更改,以便隐藏的accessoryView不会点击。
答案 1 :(得分:2)
无论硬件键盘是否存在,要正确调整视图大小,我都会调整this answer中的代码:
- (void)keyboardDidShow:(NSNotification *)aNotification {
CGRect keyboardBeginFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect keyboardEndFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
float keyboardHeight = ABS(keyboardBeginFrame.origin.y - keyboardEndFrame.origin.y); // the keyboard will move by an amount equal to its height when it appears; ABS is needed for upside-down orientations
// now you can resize your views based on keyboardHeight
// that will be the height of the inputAccessoryView if a hardware keyboard is present
}
如果您想让inputAccessoryView可见,那就是您所需要的。为了隐藏它,我认为您需要设置一个实例变量,以便您可以在keyboardDidShow中访问它:
UIView *currentInputAccessoryView;
- (void)textFieldDidBeginEditing:(UITextField *)textField {
self.currentInputAccessoryView = textField.inputAccessoryView;
}
- (void)textViewDidBeginEditing:(UITextView *)textView {
self.currentInputAccessoryView = textView.inputAccessoryView;
}
- (void)keyboardDidShow:(NSNotification *)aNotification {
CGRect keyboardBeginFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect keyboardEndFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
float keyboardHeight = ABS(keyboardBeginFrame.origin.y - keyboardEndFrame.origin.y); // the keyboard will move by an amount equal to its height when it appears; ABS is needed for upside-down orientations
if (keyboardHeight == 44) {
self.currentInputAccessoryView.hidden = YES;
keyboardHeight = 0;
}
// now you can resize your views based on keyboardHeight
// that will be 0 if a hardware keyboard is present
}
答案 2 :(得分:0)
我解决此问题的最后方法是简单地为UIKeyboardWillShowNotification
...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil];
..并隐藏先前存储在实例变量中的inputAccessoryView
。
// Called when the UIKeyboardWillShowNotification is sent.
- (void)keyboardWillShow:(NSNotification*)notification
{
NSLog(@"keyboardWillShow");
// get the frame end user info key
CGRect kbEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
// calculate the visible portion of the keyboard on the screen
CGFloat height = [[UIScreen mainScreen] bounds].size.height - kbEndFrame.origin.y;
// check if there is a input accessorry view (and no keyboard visible, e.g. hardware keyboard)
if (self.activeTextField && height <= self.activeTextField.inputAccessoryView.frame.size.height) {
NSLog(@"hardware keyboard");
self.activeTextField.inputAccessoryView.hidden = YES;
} else {
NSLog(@"software keyboard");
self.activeTextField.inputAccessoryView.hidden = NO;
}
}
事实证明,问题是由我在其getter方法中动态创建自定义inputAccessoryView
子类的UITextField
引起的。每次调用getter时我无意中重新创建视图,而不是重复使用实例变量和惰性实例化。这导致我对视图的所有分配都被忽略,因为当访问文本字段并显示键盘时,显然getter方法将被称为多次,因此视图保持被覆盖< / strong>在我的任务之后。 通过将视图保存到实例变量来重用视图解决了此问题。