ios 如何检测 iPad 上是否存在外部键盘?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2893267/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I detect if an external keyboard is present on an iPad?
提问by carloe
Is there a way to detect if an external (bluetooth or usb) keyboard is connected to the iPad?
有没有办法检测外部(蓝牙或 USB)键盘是否连接到 iPad?
采纳答案by kennytm
An indirect and SDK-safe way is to make a text field a first responder. If the external keyboard is present, the UIKeyboardWillShowNotification
local notification shall not be posted.
一种间接且 SDK 安全的方法是将文本字段设为第一响应者。如果存在外部键盘,则UIKeyboardWillShowNotification
不应发布本地通知。
Update:This is no longer true since iOS 9, however you may use the keyboard dimensions to determine if a hardware or software keyboard is involved. See How to reliably detect if an external keyboard is connected on iOS 9?for details.
更新:自 iOS 9 起不再如此,但是您可以使用键盘尺寸来确定是否涉及硬件或软件键盘。请参阅如何可靠地检测 iOS 9 上是否连接了外部键盘?详情。
You can listen to the "GSEventHardwareKeyboardAttached"
(kGSEventHardwareKeyboardAvailabilityChangedNotification
) Darwin notification, but this is a private API, so it's possible your app will get rejected if you use this. To check if the external hardware is present, use the private GSEventIsHardwareKeyboardAttached()
function.
您可以收听"GSEventHardwareKeyboardAttached"
( kGSEventHardwareKeyboardAvailabilityChangedNotification
) Darwin 通知,但这是一个私有 API,因此如果您使用它,您的应用程序可能会被拒绝。要检查外部硬件是否存在,请使用私有GSEventIsHardwareKeyboardAttached()
函数。
UIKit listens to this and sets the UIKeyboardImpl.isInHardwareKeyboardMode
property accordingly, but again this is private API.
UIKit 会侦听此内容并相应地设置UIKeyboardImpl.isInHardwareKeyboardMode
属性,但这又是私有 API。
回答by user721239
There is another level to this.
这还有另一个层面。
- If you don't have an inputAccessoryView, you won't get the notification as the above explanations point out.
- However, if you have set up an inputAccessoryView for the text view, then you will still receive a UIKeyboard notification when the external kbd is present -- the logic being that you will need to animate your view into the right location so you need the animation information contained in the notification.
- 如果您没有 inputAccessoryView,您将不会收到上述解释所指出的通知。
- 但是,如果您为文本视图设置了 inputAccessoryView,那么当存在外部 kbd 时,您仍然会收到 UIKeyboard 通知——逻辑是您需要将视图动画到正确的位置,以便您需要动画通知中包含的信息。
Fortunately, there is enough information in the event to figure out whether the kbd will be presented, though it's still a little involved.
幸运的是,事件中有足够的信息来确定 kbd 是否会出现,尽管它仍然有点牵扯。
If we examine the notification dictionary we see this information:
如果我们检查通知字典,我们会看到以下信息:
UIKeyboardFrameBeginUserInfoKey = NSRect: {{0, 1024}, {768, 308}}
UIKeyboardFrameEndUserInfoKey = NSRect: {{0, 980}, {768, 308}}
That was in Portrait; if we rotate the device to PortraitUpsideDown we get:
那是在肖像中;如果我们将设备旋转到 PortraitUpsideDown,我们会得到:
UIKeyboardFrameBeginUserInfoKey = NSRect: {{0, -308}, {768, 308}}
UIKeyboardFrameEndUserInfoKey = NSRect: {{0, -264}, {768, 308}}
Similarly in LandscapeLeft and LandscapeRight we get different start and end locations.
同样在 LandscapeLeft 和 LandscapeRight 中,我们得到不同的开始和结束位置。
Hmm... what do these numbers mean? You can see that the kbd is offscreen to start, but it does move a little. To make things worse, depending on the device orientation, the kbd locations are different.
嗯……这些数字是什么意思?您可以看到 kbd 在屏幕外启动,但它确实移动了一点。更糟糕的是,根据设备方向,kbd 位置是不同的。
However, we do have enough information to figure out what's going on:
但是,我们确实有足够的信息来弄清楚发生了什么:
- The kbd moves from just offscreen at the physical bottom of the device to the same height as the inputAccessoryView (but obscured by it)
- So in the Portrait case it moves from 1024 to 980 -- we must have an inputAccessoryView with a height of 44, which is indeed the case.
- So in Portrait if the end y + the inputAccessoryView height == screen height, then the kbd is not visible. You need to handle the other rotations, but that's the idea.
- kbd 从设备物理底部的屏幕外移动到与 inputAccessoryView 相同的高度(但被它遮挡)
- 因此,在 Portrait 情况下,它从 1024 移动到 980 —— 我们必须有一个高度为 44 的 inputAccessoryView,确实如此。
- 所以在 Portrait 中如果结束 y + inputAccessoryView 高度 == 屏幕高度,那么 kbd 是不可见的。您需要处理其他旋转,但这就是想法。
回答by T.J.
Building on @user721239 the if condition determines if the bottom of the keyboard is out of the the frame of self.view. "convertRect" normalizes the frame for any orientation.
以@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);
回答by user1172004
Even using an inputAccessoryView on your UITextView instance set to an instance of a UIView with frame CGRectZero works to get delivery of the keyboard notifications working with a hardware keyboard.
即使在 UITextView 实例上使用 inputAccessoryView 设置为具有框架 CGRectZero 的 UIView 实例,也可以使用硬件键盘传递键盘通知。
回答by philipkd
This is the code I use to get the height from the keyboard userInfo in UIKeyboardWillShowNotification
. Works if with both physical and virtual keyboards.
这是我用来从键盘 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;
回答by Mark
Based upon this thread, I've assembled two static methods that I can easily call from keyboard notification methods to handle properly resizing views (usually UIScrollViews) when a keyboard appears, regardless of type (software vs hardware):
基于这个线程,我组装了两个静态方法,我可以很容易地从键盘通知方法调用它们,以便在键盘出现时处理正确调整大小的视图(通常是 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;
}
回答by Vlad
You can use the following which also calculates the height for keyboard/toolbar height when hardware keyboard is connected. You will need to subscribe to KeyboardWillShow notification:
您可以使用以下方法计算连接硬件键盘时键盘/工具栏高度的高度。您需要订阅 KeyboardWillShow 通知:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
then handle the notification like so:
然后像这样处理通知:
- (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
// ....
}
You can also handle KeyboardWillHide notification. This will be fire when the firstResponder for both hardware and software keyboard.
您还可以处理 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
// ...
}
Also don't forget to remove observer:
也不要忘记删除观察者:
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
回答by Rivera
As most of the methods in the previous answers have been deprecated with iOS 8 and 9 I intersect the keyboard reported frame with the current window to get the actual visible keyboard frame. Then you can just check if the height has changed.
由于之前答案中的大多数方法已被 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!
}
回答by user1263865
This is not a direct answer for detecting if an external keyboard is present, but I'm doing this to detect the actual height that is needed to display the keyboard-related view(s) at the bottom of the screen.
这不是检测是否存在外部键盘的直接答案,但我这样做是为了检测在屏幕底部显示与键盘相关的视图所需的实际高度。
CGRect keyboardFrame = [[[notification userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
CGFloat keyboardRelatedViewsHeight = self.view.window.frame.size.height - keyboardFrame.origin.y;
回答by Paul Linsay
The following code gives you the keyboard frame for all orientations whether you're using a full screen view or the detail view of a split view.
以下代码为您提供所有方向的键盘框架,无论您使用的是全屏视图还是拆分视图的详细视图。
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;
The keyboard frame delivered by the notification is always in terms of hardware coordinates with the origin as the upper right corner of the screen when the iOS device in normal portrait mode with the home button at the bottom. The method -convertRect:fromView changes the coordinates from the window coordinates ( = hardware) to the local view coordinates.
当iOS设备处于正常竖屏模式且home键在底部时,通知传递的键盘边框始终以硬件坐标为原点,屏幕右上角为原点。方法 -convertRect:fromView 将坐标从窗口坐标(=硬件)更改为本地视图坐标。
I found that with a Bluetooth keyboard you get one UIKeyboardDidShowNotification the first time that there's a screen rotation but none after that. Makes it harder to distinguish the docked keyboard from the undocked/split and BT keyboards.
我发现使用蓝牙键盘,您在第一次屏幕旋转时会收到一个 UIKeyboardDidShowNotification,但之后就没有了。使对接键盘与非对接/拆分和 BT 键盘更难区分。