Как я могу определить наличие внешней клавиатуры на iPad? - PullRequest
51 голосов
/ 24 мая 2010

Есть ли способ определить, подключена ли к iPad внешняя клавиатура (Bluetooth или USB)?

Ответы [ 11 ]

34 голосов
/ 24 мая 2010

Косвенным и безопасным для SDK способом является сделать текстовое поле первым респондентом.При наличии внешней клавиатуры локальное уведомление UIKeyboardWillShowNotification не публикуется.

Обновление: Это больше не так с iOS 9, однако вы можете использовать размеры клавиатуры, чтобы определить, используется ли аппаратная или программная клавиатура.См. Как надежно определить, подключена ли внешняя клавиатура на iOS 9? для получения подробной информации.

Вы можете прослушать "GSEventHardwareKeyboardAttached" (kGSEventHardwareKeyboardAvailabilityChangedNotification) Уведомление Дарвина, но это частный API, поэтому возможно, что ваше приложение будет отклонено, если вы воспользуетесь этим.Чтобы проверить наличие внешнего оборудования, используйте частную функцию GSEventIsHardwareKeyboardAttached().

UIKit прослушивает это и соответственно устанавливает свойство UIKeyboardImpl.isInHardwareKeyboardMode, но опять-таки это частный API.

28 голосов
/ 23 апреля 2011

Есть еще один уровень для этого.

  • Если у вас нет inputAccessoryView, вы не получите уведомление, как указывают приведенные выше объяснения.
  • Однако, если вы настроили inputAccessoryView для текстаview, тогда вы все равно будете получать уведомление 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 разные.

Тем не менее, у нас достаточно информации, чтобы выяснить, что происходит:

  1. КБД перемещается от физического экрана внизу устройства к той же высоте, что и inputAccessoryView (но затенено им)
  2. Так что в случае Портрета он перемещается с 1024 на 980 - у нас должен быть inputAccessoryView с высотой 44, что действительно имеет место.
  3. Так в Портретеесли конец y + высота inputAccessoryView == высота экрана, то kbd не отображается.Вам нужно справиться с другими поворотами, но это идея.
8 голосов
/ 26 февраля 2014

Опираясь на @ 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);
5 голосов
/ 04 марта 2012

Даже при использовании inputAccessoryView на вашем экземпляре UITextView, установленном на экземпляр UIView с фреймом, CGRectZero работает для получения уведомлений клавиатуры, работающих с аппаратной клавиатурой.

4 голосов
/ 14 сентября 2012

Это код, который я использую для получения высоты от клавиатуры 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;
3 голосов
/ 13 июля 2013

Основываясь на этом потоке, я собрал два статических метода, которые я могу легко вызвать из методов уведомлений клавиатуры для обработки правильно изменяющих размеры представлений (обычно UIScrollViews) при появлении клавиатуры независимо от типа (программное обеспечение или аппаратное обеспечение):

+ (void)keyboardWillShowHide:(NSNotification *)notification
                  inView:(UIView *)view
              adjustView:(UIView *)viewToAdjust
{
    // How much should we adjust the view's 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's 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;
}
2 голосов
/ 26 мая 2016

Вы можете использовать следующее, которое также вычисляет высоту для высоты клавиатуры / панели инструментов, когда подключена аппаратная клавиатура.Вам нужно будет подписаться на уведомление 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.Это будет срабатывать, когда firstResponder для аппаратной и программной клавиатуры.

- (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];
}
1 голос
/ 11 апреля 2016

Поскольку большинство методов в предыдущих ответах устарели в 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!
}
0 голосов
/ 13 апреля 2016

Это не прямой ответ для определения наличия внешней клавиатуры, но я делаю это для определения фактической высоты, необходимой для отображения связанных с клавиатуры представлений в нижней части экрана.

CGRect keyboardFrame = [[[notification userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
CGFloat keyboardRelatedViewsHeight = self.view.window.frame.size.height - keyboardFrame.origin.y;
0 голосов
/ 11 декабря 2014

@ Философский ответ сработал для меня. Решение менее сложное на 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...