Как надежно определить, подключена ли внешняя клавиатура на iOS 9? - программирование
Подтвердить что ты не робот

Как надежно определить, подключена ли внешняя клавиатура на iOS 9?

Ранее для iOS 9 самым надежным методом определения того, подключена ли внешняя клавиатура, является прослушивание UIKeyboardWillShowNotification и создание текстового поля первым ответчиком, как описано в this вопрос. Уведомление будет срабатывать при использовании виртуальной клавиатуры, но не будет срабатывать при использовании внешней клавиатуры.

Однако это поведение теперь изменилось с iOS 9. UIKeyboardWillShowNotification также срабатывает, когда подключена внешняя клавиатура, так как теперь отображается новая панель инструментов клавиатуры.

По-прежнему можно определить высоту клавиатуры и принять решение, будет ли отображаться меньшая панель инструментов или большая виртуальная клавиатура. Однако этот метод не является надежным, поскольку высота клавиатуры изменилась между различными бета-версиями и не может считаться неизменной с течением времени.

Есть ли более надежный метод, который можно использовать с iOS 9?

4b9b3361

Ответ 1

Вернувшись к исходному вопросу, я нашел решение, которое работает.

Кажется, что когда отображается обычная виртуальная клавиатура, рамка клавиатуры находится в пределах размеров экрана. Однако, когда подключена физическая клавиатура и отображается панель инструментов клавиатуры, рамка клавиатуры находится за пределами экрана. Мы можем проверить, находится ли рамка клавиатуры вне экрана, чтобы определить, отображается ли панель инструментов клавиатуры.

Objective-C

- (void) keyboardWillShow:(NSNotification *)notification {
    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;

    if ((keyboard.origin.y + keyboard.size.height) > height) {
        self.hasKeyboard = YES;
    }
}

Swift

@objc func keyboardWillShow(_ notification: NSNotification) {
    guard let userInfo = notification.userInfo else {return}
    let keyboardScreenEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    let keyboard = self.view.convert(keyboardScreenEndFrame, from: self.view.window)
    let height = self.view.frame.size.height
    if (keyboard.origin.y + keyboard.size.height) > height {
        self.hasKeyboard = true
    }
}

Ответ 2

Этот код поддерживает iOS 8 и iOS 9, inputAccessoryView, имеет двойную защищенную константу, которая будет готова для новых изменений в будущих версиях iOS и для поддержки новых устройств:

#define gThresholdForHardwareKeyboardToolbar 160.f // it minimum height of the software keyboard on non-retina iPhone in landscape mode

- (bool)isHardwareKeyboardUsed:(NSNotification*)keyboardNotification {
    NSDictionary* info = [keyboardNotification userInfo];
    CGRect keyboardEndFrame;
    [[info valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
    float height = [[UIScreen mainScreen] bounds].size.height - keyboardEndFrame.origin.y;
    return height < gThresholdForHardwareKeyboardToolbar;
}

Примечание. Аппаратная клавиатура может присутствовать, но не использоваться.

Ответ 3

Я использую вариант ответа Сары Элан. У меня возникли проблемы с ее подходом в определенных взглядах. Я так и не добрался до сути проблемы. Но вот еще один способ определить, является ли это клавиатурой "undo" внешней клавиатуры ios9, а не полноразмерной клавиатурой.

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

//... somewhere ...
#define HARDWARE_KEYBOARD_SIZE_IOS9 55 
//

+ (BOOL) isExternalKeyboard:(NSNotification*)keyboardNotification {

  NSDictionary* info = [keyboardNotification userInfo];
  CGRect keyboardEndFrame;
  [[info valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
  CGRect keyboardBeginFrame;
  [[info valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardBeginFrame];

  CGFloat diff = keyboardEndFrame.origin.y - keyboardBeginFrame.origin.y;
  return fabs(diff) == HARDWARE_KEYBOARD_SIZE_IOS9;
}

Ответ 4

Частное API-решение: (нужно захватить частный заголовочный файл - использовать RuntimeViewer).

Хорошо работает для корпоративных приложений, где у вас нет ограничений AppStore.

#import "UIKit/UIKeyboardImpl.h"

+ (BOOL)isHardwareKeyboardMode
{
   UIKeyboardImpl *kbi = [UIKeyboardImpl sharedInstance];
   BOOL externalKeyboard = kbi.inHardwareKeyboardMode;
   NSLog(@"Using external keyboard? %@", [email protected]"YES":@"NO");
   return externalKeyboard;
}

Ответ 5

Если вы сделаете панель инструментов неактуальной, клавиатура не появится. Сделайте это, отключив левую и правую группы (по крайней мере, в iOS 12.4):

textField.inputAssistantItem.leadingBarButtonGroups = []
textField.inputAssistantItem.trailingBarButtonGroups = []

... и если это поможет, это быстрый способ наблюдения:

// Watch for a soft keyboard to show up
let observer = NotificationCenter.default.addObserver(forName: UIWindow.keyboardWillShowNotification, object: nil, queue: nil) { notification in
    print("no external keyboard")
}

// Stop observing shortly after, since the keyboard should have shown by now
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    NotificationCenter.default.removeObserver(observer)
}

Ответ 6

Вы можете подписаться на уведомление при подключении внешнего устройства:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceConnected:) name:EAAccessoryDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceDisconnected:) name:EAAccessoryDidDisconnectNotification object:nil];
[[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications];

Или просто получить список подключенных устройств:

EAAccessoryManager* accessoryManager = [EAAccessoryManager sharedAccessoryManager];

if (accessoryManager)
{
    NSArray* connectedAccessories = [accessoryManager connectedAccessories];
    NSLog(@"ConnectedAccessories = %@", connectedAccessories);
}

Ответ 7

Вы можете попробовать проверить периферийные устройства, которые являются рекламными услугами, используя Core Bluetooth

CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; 
[centralManager scanForPeripheralsWithServices:nil options:nil];

И вы должны реализовать делегат:

- (void)centralManager:(CBCentralManager * _Nonnull)central
 didDiscoverPeripheral:(CBPeripheral * _Nonnull)peripheral
     advertisementData:(NSDictionary<NSString *,
                                id> * _Nonnull)advertisementData
                  RSSI:(NSNumber * _Nonnull)RSSI{

}