外部(BluetoothまたはUSB)キーボードがiPadに接続されているかどうかを検出する方法はありますか?
間接的でSDKセーフな方法は、テキストフィールドをファーストレスポンダーにすることです。外部キーボードが存在する場合、UIKeyboardWillShowNotification
ローカル通知は送信されません。
更新:これはiOS 9以降では事実ではありませんが、キーボードの寸法を使用してハードウェアまたはソフトウェアのキーボードが関係しているかどうかを判断できます。詳細については、iOS 9で外部キーボードが接続されているかどうかを確実に検出する方法を参照してください。
_"GSEventHardwareKeyboardAttached"
_(kGSEventHardwareKeyboardAvailabilityChangedNotification
)Darwin通知を聞くことができますが、これはプライベートAPIであるため、これを使用するとアプリが拒否される可能性があります。外部ハードウェアが存在するかどうかを確認するには、プライベートGSEventIsHardwareKeyboardAttached()
関数を使用します。
UIKitはこれをリッスンし、それに応じて_UIKeyboardImpl.isInHardwareKeyboardMode
_プロパティを設定しますが、これもプライベートAPIです。
これには別のレベルがあります。
幸いなことに、イベントには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の場所が異なります。
ただし、何が起こっているかを把握するのに十分な情報があります。
@ 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);
フレームCGRectZeroでUIViewのインスタンスに設定されたUITextViewインスタンスでinputAccessoryViewを使用しても、ハードウェアキーボードで動作するキーボード通知の配信を取得できます。
これは、UIKeyboardWillShowNotification
のキーボードuserInfoから高さを取得するために使用するコードです。物理キーボードと仮想キーボードの両方で機能します。
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;
このスレッドに基づいて、キーボード通知メソッドから簡単に呼び出して、タイプ(ソフトウェアとハードウェア)に関係なく、キーボードが表示されたときにビュー(通常はUIScrollViews)の適切なサイズ変更を処理できる2つの静的メソッドを組み立てました:
+ (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;
}
以下を使用して、ハードウェアキーボードが接続されている場合のキーボード/ツールバーの高さも計算できます。 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];
}
前の回答のほとんどのメソッドは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!
}
次のコードは、全画面表示を使用している場合でも、分割表示の詳細表示を使用している場合でも、すべての方向のキーボードフレームを提供します。
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デバイスが通常のポートレートモードで、ホームボタンが下部にある場合、Originを画面の右上隅とするハードウェア座標に基づいています。メソッド-convertRect:fromViewは、座標をウィンドウ座標(=ハードウェア)からローカルビュー座標に変更します。
Bluetoothキーボードを使用すると、画面の回転はあるがその後はないという初めてのUIKeyboardDidShowNotificationを取得することがわかりました。ドッキングされたキーボードと、ドッキングされていない/スプリットおよびBTキーボードを区別しにくくします。
これは、外部キーボードが存在するかどうかを検出するための直接的な答えではありませんが、画面の下部にキーボード関連のビューを表示するために必要な実際の高さを検出するためにこれを行っています。
CGRect keyboardFrame = [[[notification userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
CGFloat keyboardRelatedViewsHeight = self.view.window.frame.size.height - keyboardFrame.Origin.y;