Есть ли способ определить, подключена ли внешняя (bluetooth или USB) клавиатура к iPad?
Как определить, присутствует ли внешняя клавиатура на iPad?
Ответ 1
Непрямой и безопасный SDK способ состоит в том, чтобы сделать текстовое поле первым ответчиком. Если внешняя клавиатура присутствует, локальное уведомление UIKeyboardWillShowNotification
не публикуется.
Вы можете прослушать уведомление "GSEventHardwareKeyboardAttached"
(kGSEventHardwareKeyboardAvailabilityChangedNotification
) Darwin, но это частный API, так что ваше приложение будет отклонено, если вы его используете. Чтобы проверить наличие внешнего оборудования, используйте закрытую функцию GSEventIsHardwareKeyboardAttached()
.
UIKit прослушивает это и устанавливает свойство UIKeyboardImpl.isInHardwareKeyboardMode
соответствующим образом, но опять же это частный API.
Ответ 2
На этом есть еще один уровень.
- Если у вас нет inputAccessoryView, вы не получите уведомление, как указано выше.
- Однако, если вы настроили inputAccessoryView для текстового представления, вы все равно получите уведомление UIKeyboard, когда присутствует внешний kbd, - логика заключается в том, что вам нужно будет оживить ваш вид в нужном месте, чтобы вы нужна информация анимации, содержащаяся в уведомлении.
К счастью, в этом случае достаточно информации, чтобы выяснить, будет ли представлен kbd, хотя он все еще немного задействован.
Если мы рассмотрим словарь уведомлений, мы увидим эту информацию:
UIKeyboardFrameBeginUserInfoKey = NSRect: {{0, 1024}, {768, 308}}
UIKeyboardFrameEndUserInfoKey = NSRect: {{0, 980}, {768, 308}}
Это было в портрете; если мы поворачиваем устройство на PortraitUpsideDown, мы получаем:
UIKeyboardFrameBeginUserInfoKey = NSRect: {{0, -308}, {768, 308}}
UIKeyboardFrameEndUserInfoKey = NSRect: {{0, -264}, {768, 308}}
Аналогично, в LandscapeLeft и LandscapeRight мы получаем разные начальные и конечные местоположения.
Хм... что означают эти цифры? Вы можете видеть, что kbd выключен для запуска, но он немного движется. Чтобы ухудшить ситуацию, в зависимости от ориентации устройства, местоположения kbd различны.
Однако у нас достаточно информации, чтобы выяснить, что происходит:
- kbd перемещается только с экрана на физическом дне устройства до той же высоты, что и inputAccessoryView (но скрывается от него).
- Итак, в случае портрета он перемещается с 1024 на 980 - у нас должен быть inputAccessoryView с высотой 44, что действительно так.
- Таким образом, в портрете, если конец y +, высота входного_выбора высоты == высота экрана, то kbd не отображается. Вам нужно обрабатывать другие вращения, но эта идея.
Ответ 3
Основываясь на @user721239, условие if определяет, находится ли нижняя часть клавиатуры вне рамки self.view. "convertRect" нормализует рамку для любой ориентации.
- (void)keyboardWillShow:(NSNotification *)notification {
keyboardFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil]; // convert orientation
keyboardSize = keyboardFrame.size;
//NSLog(@"keyboardFrame.origin.y = %f", keyboardFrame.origin.y);
//NSLog(@"keyboardFrame.size.height = %f", keyboardFrame.size.height);
BOOL hardwareKeyboardPresent = FALSE;;
if ((keyboardFrame.origin.y + keyboardFrame.size.height) > (self.view.frame.size.height+self.navigationController.navigationBar.frame.size.height)) {
hardwareKeyboardPresent = TRUE;
}
//NSLog(@"bottomOfKeyboard = %f", bottomOfKeyboard);
//NSLog(@"self.view.frame.size.height = %f", self.view.frame.size.height);
Ответ 4
Даже используя inputAccessoryView в экземпляре UITextView, установленном на экземпляр UIView с фреймом, CGRectZero работает, чтобы получить доставку уведомлений клавиатуры, работающих с аппаратной клавиатурой.
Ответ 5
Это код, который я использую для получения высоты с клавиатуры userInfo в UIKeyboardWillShowNotification
. Работает как с физической, так и с виртуальной клавиатурой.
NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect = [aValue CGRectValue];
CGFloat deviceHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat deviceWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat newKeyboardHeight;
if (interfaceOrientation == UIInterfaceOrientationPortrait)
newKeyboardHeight = deviceHeight - keyboardRect.origin.y;
else if (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
newKeyboardHeight = keyboardRect.size.height + keyboardRect.origin.y;
else if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
newKeyboardHeight = deviceWidth - keyboardRect.origin.x;
else
newKeyboardHeight = keyboardRect.size.width + keyboardRect.origin.x;
Ответ 6
Основываясь на этом потоке, я собрал два статических метода, которые я могу легко вызвать из методов уведомления клавиатуры, чтобы обрабатывать правильное изменение размеров представлений (обычно UIScrollViews), когда появляется клавиатура, независимо от типа (программное обеспечение и аппаратное обеспечение):
+ (void)keyboardWillShowHide:(NSNotification *)notification
inView:(UIView *)view
adjustView:(UIView *)viewToAdjust
{
// How much should we adjust the view frame by?
CGFloat yOffset = [SMKeyboardUtil keyboardOffsetForKeyboardNotification:notification
inView:view];
CGRect viewFrame = viewToAdjust.frame;
viewFrame.size.height -= yOffset;
// Get the animation parameters being used to show the keyboard. We'll use the same animation parameters as we
// resize our view.
UIViewAnimationCurve animationCurve;
NSTimeInterval animationDuration;
[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
// Resize the view frame to subtract/add the height of the keyboard (and any inputAccessoryView)
[UIView beginAnimations:@"animate resiz view" context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[viewToAdjust setFrame:viewFrame];
[UIView commitAnimations];
}
+ (CGFloat)keyboardOffsetForKeyboardNotification:(NSNotification *)notification
inView:(UIView *)view
{
NSAssert(notification.userInfo[UIKeyboardFrameBeginUserInfoKey], @"Invalid keyboard notification");
// Get the frame of keyboard from the notification
CGRect keyboardFrameBeginRaw = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect keyboardFrameEndRaw = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// Because the frame we get from the notification is raw screen coordinates, without accounting for device orientation,
// we need to convert the frame to be relative to our view.
CGRect keyboardFrameBegin = [view convertRect:keyboardFrameBeginRaw fromView:nil];
CGRect keyboardFrameEnd = [view convertRect:keyboardFrameEndRaw fromView:nil];
// We could examine the size of the frame, but this does not account for hardware keyboards. Instead,
// we need to need the delta between the start and end positions to determine how much to modify
// the size of our view.
return keyboardFrameBegin.origin.y - keyboardFrameEnd.origin.y;
}
Ответ 7
Вы можете использовать следующее, которое также вычисляет высоту для высоты клавиатуры/панели инструментов при подключении аппаратной клавиатуры. Вам нужно будет подписаться на уведомление KeyboardWillShow:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
затем обработайте уведомление следующим образом:
- (void)keyboardWillShow:(NSNotification *)notification
{
// Information we want to determine from notification
BOOL isHardwareKB = NO;
CGFloat keyboardHeight;
// Notification info
NSDictionary* userInfo = [notification userInfo];
CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboard = [self.view convertRect:keyboardFrame fromView:self.view.window];
CGFloat height = self.view.frame.size.height;
// Determine if hardware keyboard fired this notification
if ((keyboard.origin.y + keyboard.size.height) > height) {
isHardwareKB = YES;
keyboardHeight = height - keyboard.origin.y; // toolbar height
} else {
isHardwareKB = NO;
// As this value can change depending on rotation
keyboardHeight = MIN(keyboardFrame.size.width, keyboardFrame.size.height);
}
// adjust view ui constraints ext ext depending on keyboard height
// ....
}
Вы также можете обрабатывать уведомление KeyboardWillHide. Это будет огонь, когда первый ответчик будет как для аппаратной, так и для программной клавиатуры.
- (void)keyboardWillShow:(NSNotification *)notification
{
// Information we want to determine from notification
BOOL isHardwareKB; // this is irrelevant since it is hidden
CGFloat keyboardHeight = 0; // height is now 0
// Do any view layout logic here for keyboard height = 0
// ...
}
Также не забудьте удалить наблюдателя:
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Ответ 8
Поскольку большинство методов предыдущих ответов устарели с iOS 8 и 9, я пересекаю рамку с сообщением клавиатуры с текущим окном, чтобы получить реальную видимую рамку клавиатуры. Затем вы можете просто проверить, изменилась ли высота.
CGRect reportedKeyboardFrameRaw = [[[notification userInfo] valueForKey: UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect reportedKeyboardFrame = [self.view.window convertRect: reportedKeyboardFrameRaw fromWindow:nil];
CGRect visibleKeyboardFrame = CGRectIntersection(reportedKeyboardFrame, self.view.window.frame);
if (reportedKeyboardFrame.size.height != visibleKeyboardFrame.size.height)
{
// External keyboard present!
}
Ответ 9
Следующий код дает вам рамку клавиатуры для всех ориентаций, используете ли вы полноэкранный режим или подробный вид разделенного вида.
NSDictionary* info = [aNotification userInfo];
CGRect frame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardEndFrame = [self.view convertRect:frame fromView:nil]; // The raw frame values are physical device coordinate.
CGSize keyboardSize = keyboardEndFrame.size;
Рамка клавиатуры, поставленная уведомлением, всегда находится в терминах аппаратных координат, а источник - в правом верхнем углу экрана, когда устройство iOS в обычном портретном режиме с кнопкой дома внизу. Метод -convertRect: fromView изменяет координаты из оконных координат (= hardware) в локальные координаты вида.
Я обнаружил, что с клавиатурой Bluetooth вы получаете один UIKeyboardDidShowNotification в первый раз, когда есть поворот экрана, но ни один после этого. Делает сложнее отличить пристыкованную клавиатуру от разблокированных/разделенных и BT-клавиатур.
Ответ 10
Это не прямой ответ для обнаружения присутствия внешней клавиатуры, но я делаю это, чтобы определить фактическую высоту, необходимую для отображения связанных с клавиатурой представлений (-ов) в нижней части экрана.
CGRect keyboardFrame = [[[notification userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
CGFloat keyboardRelatedViewsHeight = self.view.window.frame.size.height - keyboardFrame.origin.y;
Ответ 11
Ответ на @philosophistry работал у меня. Решение на IOS 8 менее сложно:
CGRect keyboardRect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat deviceHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat keyboardHeight = deviceHeight - keyboardRect.origin.y;
NSLog(@"actualKeyboardHeight = %f", keyboardHeight);