IOS 9以前では、外部キーボードが接続されているかどうかを判断する最も信頼できる方法は、UIKeyboardWillShowNotification
をリッスンし、 この質問で説明したように、テキストフィールドを最初のレスポンダーにすることでした 。この通知は、仮想キーボードを使用すると起動しますが、外部キーボードを使用すると起動しません。
ただし、この動作はiOS 9で変更されました。新しいキーボードツールバーが表示されるようになったため、外部キーボードが接続されるとUIKeyboardWillShowNotification
も起動します。
キーボードの高さを検出し、表示されているのが小さいツールバーであるか大きい仮想キーボードであるかを判断することは依然として可能です。ただし、この方法は、キーボードの高さがさまざまなベータ版の間で変更されており、時間の経過とともに同じ状態を維持することはできないため、信頼できません。
IOS 9で使用できるより信頼性の高い方法はありますか?
元の質問に戻った後、動作する解決策を見つけました。
通常の仮想キーボードが表示されるとき、キーボードフレームは画面の寸法内にあるようです。ただし、物理キーボードが接続され、キーボードツールバーが表示されている場合、キーボードフレームは画面外にあります。キーボードフレームが画面外にあるかどうかを確認して、キーボードツールバーが表示されているかどうかを判断できます。
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;
}
}
スウィフト
@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
}
}
このコードは、iOS 8およびiOS 9、inputAccessoryViewをサポートし、iOSの将来のバージョンでの新しい変更に対応し、新しいデバイスをサポートするために、二重に保護された定数を持っています。
#define gThresholdForHardwareKeyboardToolbar 160.f // it's 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;
}
ハードウェアキーボードが表示される場合がありますが、使用されないことに注意してください。
プライベートAPIソリューション:(プライベートヘッダーファイルを取得する必要があります-RuntimeViewerを使用します)。
AppStoreの制限がないエンタープライズアプリに最適です。
#import "UIKit/UIKeyboardImpl.h"
+ (BOOL)isHardwareKeyboardMode
{
UIKeyboardImpl *kbi = [UIKeyboardImpl sharedInstance];
BOOL externalKeyboard = kbi.inHardwareKeyboardMode;
NSLog(@"Using external keyboard? %@", externalKeyboard?@"YES":@"NO");
return externalKeyboard;
}
サラ・エランの答えのバリエーションを使用しています。私は特定の見解で彼女のアプローチに問題を抱えていました。問題の原因を突き止めることはできませんでした。ただし、これがフルサイズのキーボードではなく、お持ちの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;
}
ツールバーを無関係にすると、キーボードが表示されなくなります。これを行うには、左と右のグループを空白にします(少なくとも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)
}
外部デバイスが接続されたときに通知をサブスクライブできます。
[[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);
}