iPad: Detecting External Keyboard
My app uses a UIAccessoryView
to provide additional keyboard functionality (such as forward/backward tabs and arrows keys) for the virtual keyboard, but that causes UIKeyboardDidShowNotification to fire even when a physical keyboard is present (the accessory appears at the bottom of the screen).
I'd like to check if a physical keyboard is attached when handling UIKeyboardWillShowNotification, to prevent the accessory view from appearing and to prevent my custom view from scrolling up (to make room for the non-existent virtual keyboard).
I've tried examining the UIKeyboardFrameEndUserInfoKey
key, but it returns a real size for the virtual keyboard, in spite of nothing being displayed.
Is there any way to detect the presence of a physical keyboard to prevent this unwanted behaviour?
Hmm, the plot thickens.
I tried disabling the input accessory by returning nil from the inputAccessoryView property of the Responder object which triggers the keyboard. That suppresses UIKeyboardWillShowNotification
and UIKeyboardDidShowNotification
when there is a physical keyboard present, but keeps these notifications when there is no such keyboard. All good so far.
Then I tried re-enabling inputAccessoryView only after UIKeyboardWillShowNotification
had been received. This only fires when a virtual keyboard is needed, so it should allow me to reintroduce the accessory view in those circumstances. Or so I thought.
Unfortunately, it seems the OS doesn't check inputAccessoryView after UIKeyboardWillShowNotification
, so it fails to show the accessory vi开发者_开发百科ew when it is needed :o(
That leaves me with two options:
- Include the input accessory view, giving extra functionality for virtual keyboard users, but lose the ability to detect a physical keyboard and hence not supporting physical devices; or
- Exclude the input accessory altogether, preventing most users from accessing the extra keys, but allowing the app to work with a physical keyboard.
Not a great choice, so I'm still keen to see if anyone else has addressed this problem!
(This answer was suggested by Sean Heber on the Apple forums)
When you get a UIKeyboardDidShowNotification
, instead of using the frame given by UIKeyboardFrameEndUserInfoKey
, simply test where the view's accessory view is and use that, instead. All I do is check to see what the frame of the accessory view is and convert it to my own view's coordinate space. Then I can easily use that frame to decide what to do.
Note: When the on-screen keyboard is shown/hidden using the bluetooth keyboard's eject button, it seems that UIKit sends UIKeyboardDidShowNotification
again but not a UIKeyboardWillHideNotification
. This is also a confusing inconsistency, but the above workaround is still valid as the system will change the frame of the inputAccessoryView when it slides in the on-screen keyboard, so you can still adjust things accordingly.
If you inspect the frame in UIKeyboardFrameEndUserInfoKey
you'll find that it is offset by the height of the keyboard when an external keyboard is attached (basically it does "appear", but never appears above the bottom of the screen), so you can convert it to your local coordinate space and intersect it with your view's bounds to find the visible height of the keyboard.
- (void)keyboardWillShow:(NSNotification *)notification {
UIView *view = [self view];
CGRect bounds = [view bounds];
CGRect keyboardFrame = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect convertedKeyboardFrame = [view convertRect:keyboardFrame fromView:nil];
CGRect intersection = CGRectIntersection(convertedKeyboardFrame, bounds);
// intersection.size.height == 0 with external keyboards
}
精彩评论