ios 如果连接了硬件键盘,则隐藏inputAccessoryView

vq8itlhq  于 2022-11-19  发布在  iOS
关注(0)|答案(4)|浏览(98)

类似于这个问题:iPad: Detecting External Keyboard,我正在开发一个iPad应用程序,它使用带有自定义inputAccessoryView的文本字段来为虚拟键盘提供附加功能。
但是,如果 * 硬件键盘 (例如蓝牙键盘)连接到设备时,软件键盘没有按预期显示,但由于某种原因,inputAccessoryView在屏幕底部 * 仍然可见 。此外,这似乎会引发UIKeyboardDidShowNotification(因此向上移动我的视图以避免被实际上不存在的键盘遮挡),即使硬件键盘用于输入。
我找到了几种检测硬件键盘是否连接的解决方案,但它们都在接收UIKeyboardDidShowNotification * 之后 * 检查状态,此时inputAccessoryView已经可见(例如How can I detect if an external keyboard is present on an iPad?)。
我正在寻找一种方法,在没有连接硬件键盘的情况下只显示inputAccessoryView。因此,我需要知道在
UIKeyboardDidShowNotification被触发之前**是否连接了硬件键盘。
这里提供的可接受的解决方案How can I detect if an external keyboard is present on an iPad?对我来说是没有选择的,因为它们使用私有API,这可能会导致我的应用程序被拒绝。

exdqitrt

exdqitrt1#

这只是@arlomedia对答案的增强,我所做的是观看willshow和didShow。
willShow我用来移动我的文本视图到适当的位置,使其移动速度与键盘相同。
我使用didShow使用上述技术检查键盘的外观大小,并相应地隐藏/显示附件InputView。

重要的是我还将该视图设置为默认隐藏,并且当收到willHide事件时,它将再次隐藏。

- (void) addKeyboardObserver {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHidden:) name:UIKeyboardWillHideNotification object:nil];
}

- (void) removeKeyboardObserver {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

- (void)keyboardWillShow:(NSNotification*)notification {
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    // If we're on iOS7 or earlier and landscape then the height is in the
    // width.
    //
    if ((IS_LANDSCAPE == YES) && (IS_IOS8_OR_LATER == NO)) {
        keyboardSize.height = keyboardSize.width;
    }

    NSNumber *rate = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey];

    CGRect textFieldFrame = self.textField.frame;
    textFieldFrame.origin.y = ([Util screenHeight] - keyboardSize.height) - textFieldFrame.size.height - [Util scaledHeight:10.0];

    // Move the text field into place.
    //
    [UIView animateWithDuration:rate.floatValue animations:^{
        self.answerTextField.frame = textFieldFrame;
    }];

    keyboardShown = YES;
}

- (void)keyboardDidShow:(NSNotification*)notification {
    CGRect keyboardBeginFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGSize keyboardSize = keyboardBeginFrame.size;

    // If we're on iOS7 or earlier and landscape then the height is in the
    // width.
    //
    if ((IS_LANDSCAPE == YES) && (IS_IOS8_OR_LATER == NO)) {
        keyboardSize.height = ABS(keyboardBeginFrame.origin.x - keyboardEndFrame.origin.x); // the keyboard will move by an amount equal to its height when it appears; ABS is needed for upside-down orientations
    } else {
        keyboardSize.height = ABS(keyboardBeginFrame.origin.y - keyboardEndFrame.origin.y); // the keyboard will move by an amount equal to its height when it appears; ABS is needed for upside-down orientations
    }

    NSNumber *rate = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey];

    [UIView animateWithDuration:rate.floatValue animations:^{
        if (keyboardSize.height <= self.accessoryBar.frame.size.height) {
            self.textField.inputAccessoryView.hidden = YES;
            self.answerTextField.inputAccessoryView.userInteractionEnabled = NO;
        } else {
            self.textField.inputAccessoryView.hidden = NO;
            self.answerTextField.inputAccessoryView.userInteractionEnabled = YES;
        }
    }];

    keyboardShown = YES;
}

- (void)keyboardHidden:(NSNotification*)notification {

    NSNumber *rate = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey];

    // Remove/hide the accessory view so that next time the text field gets focus, if a hardware
    // keyboard is used, the accessory bar is not shown.
    //
    [UIView animateWithDuration:rate.floatValue animations:^{
        self.textField.inputAccessoryView.hidden = YES;
        self.answerTextField.inputAccessoryView.userInteractionEnabled = NO;
    }];

    keyboardShown = NO;
}

注意编辑以添加对userInteractionEnabled的更改,以便隐藏的附件视图不会吃掉点击。

monwx1rj

monwx1rj2#

IIRC,当软键盘出现时,视图不会自动调整大小。我正在通过一个由UIKeyboardDidShow通知触发的keyboardDidShow方法来调整视图大小。因此,在该方法中检测硬件和软件键盘应该足够了,然后您可以跳过表格调整大小并隐藏输入辅助视图(或者调整表格大小以适应输入辅助视图,如果您更喜欢使其可见)。
无论是否存在硬件键盘,为了正确地调整视图大小,我修改了this answer中的代码:

- (void)keyboardDidShow:(NSNotification *)aNotification {
    CGRect keyboardBeginFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGRect keyboardEndFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    float keyboardHeight = ABS(keyboardBeginFrame.origin.y - keyboardEndFrame.origin.y); // the keyboard will move by an amount equal to its height when it appears; ABS is needed for upside-down orientations

    // now you can resize your views based on keyboardHeight
    // that will be the height of the inputAccessoryView if a hardware keyboard is present
}

如果你想让inputAccessoryView保持可见,这就是你所需要的。要隐藏它,我认为你需要设置一个示例变量,这样你就可以在keyboardDidShow中访问它:

UIView *currentInputAccessoryView;

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    self.currentInputAccessoryView = textField.inputAccessoryView;
}

- (void)textViewDidBeginEditing:(UITextView *)textView {
    self.currentInputAccessoryView = textView.inputAccessoryView;
}

- (void)keyboardDidShow:(NSNotification *)aNotification {
    CGRect keyboardBeginFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGRect keyboardEndFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    float keyboardHeight = ABS(keyboardBeginFrame.origin.y - keyboardEndFrame.origin.y); // the keyboard will move by an amount equal to its height when it appears; ABS is needed for upside-down orientations

    if (keyboardHeight == 44) {
        self.currentInputAccessoryView.hidden = YES;
        keyboardHeight = 0;
    }

    // now you can resize your views based on keyboardHeight
    // that will be 0 if a hardware keyboard is present
}
b0zn9rqh

b0zn9rqh3#

我解决这个问题的最后一个方法是简单地为UIKeyboardWillShowNotification添加一个观察者...

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification object:nil];

..并隐藏先前存储在示例变量中的inputAccessoryView

// Called when the UIKeyboardWillShowNotification is sent.
- (void)keyboardWillShow:(NSNotification*)notification
{
    NSLog(@"keyboardWillShow");

    // get the frame end user info key
    CGRect kbEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

    // calculate the visible portion of the keyboard on the screen
    CGFloat height = [[UIScreen mainScreen] bounds].size.height - kbEndFrame.origin.y;

    // check if there is a input accessorry view (and no keyboard visible, e.g. hardware keyboard)
    if (self.activeTextField && height <= self.activeTextField.inputAccessoryView.frame.size.height) {

        NSLog(@"hardware keyboard");

        self.activeTextField.inputAccessoryView.hidden = YES;
    } else {

        NSLog(@"software keyboard");

        self.activeTextField.inputAccessoryView.hidden = NO;
    }
}

原来这个问题是由我在getter方法中动态创建我的自定义UITextField子类的inputAccessoryView引起的。我无意中在每次调用getter时重新创建了视图,而不是在惰性示例化中重用示例变量。这导致我对视图的所有赋值都被忽略,因为显然getter方法将被多次调用当访问文本字段时,键盘显示,因此视图在我的分配后被覆盖通过将视图保存到示例变量来重用视图修复了此问题。

ia2d9nvy

ia2d9nvy4#

这是一个旧的线程,但截至iOS 14,我们现在有适当的API通过GameController框架使用GCKeyboardGCKeyboardDidConnect/GCKeyboardDidDisconnect通知跟踪硬件键盘。
在这个隐藏和显示inputAccessoryView的特殊情况下,您可以执行如下操作:

import GameController

class ViewController: UIViewController {
    ...
    var isHardwareKeyboardConnected: Bool {
        didSet {
            enableInputAccessoryIfNeeded()
        }
    }

    func enableInputAccessoryIfNeeded() {
        textField.inputAccessoryView = isHardwareKeyboardConnected ? nil : textFielInputAccessoryView
        textField.reloadInputViews()
    }

    init() {
        isHardwareKeyboardConnected = GCKeyboard.coalesced != nil
        super.init(nibName: nil, bundle: nil)
        startObservingHardwareKeyboard()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        enableInputAccessoryIfNeeded()
    }

    func startObservingHardwareKeyboard() {
        NotificationCenter.default.addObserver(self, selector: #selector(hardwareKeyboardDidConnect), name: .GCKeyboardDidConnect, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(hardwareKeyboardDidDisconnect), name: .GCKeyboardDidDisconnect, object: nil)
    }

    @objc func hardwareKeyboardDidConnect(_ notification: Notification) {
        print("[Keyboard] Hardware keyboard did connect")
        isHardwareKeyboardConnected = true
    }

    @objc func hardwareKeyboardDidDisconnect(_ notification: Notification) {
        print("[Keyboard] Hardware keyboard did disconnect")
        isHardwareKeyboardConnected = false
    }
}

相关问题