开发者

iOS: How to access the `UIKeyboard`?

开发者 https://www.devze.com 2023-03-15 04:07 出处:网络
I want to get a pointer reference to UIKeyboard *keyboard to the keyboard on screen so that I can add a transparent subview to it, covering it completely, to achieve the effect of disabling the UIKeyb

I want to get a pointer reference to UIKeyboard *keyboard to the keyboard on screen so that I can add a transparent subview to it, covering it completely, to achieve the effect of disabling the UIKeyboard without hiding it.

In doing this, can I assume that there's only one UIKeyboard on the screen at a time? I.e., is it a singleton? Where's the method [UIKeyboard sharedInstance]. Brownie开发者_开发知识库 points if you implement that method via a category. Or, even more brownie points if you convince me why it's a bad idea to assume only one keyboard and give me a better solution.


Try this:

// my func
- (void) findKeyboard {

    // Locate non-UIWindow.
    UIWindow *keyboardWindow = nil;
    for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
        if (![[testWindow class] isEqual:[UIWindow class]]) {
           keyboardWindow = testWindow;
           break;
       }
    }

    // Locate UIKeyboard.  
    UIView *foundKeyboard = nil;
    for (UIView *possibleKeyboard in [keyboardWindow subviews]) {

        // iOS 4 sticks the UIKeyboard inside a UIPeripheralHostView.
        if ([[possibleKeyboard description] hasPrefix:@"<UIPeripheralHostView"]) {
            possibleKeyboard = [[possibleKeyboard subviews] objectAtIndex:0];
        }                                                                                

        if ([[possibleKeyboard description] hasPrefix:@"<UIKeyboard"]) {
           foundKeyboard = possibleKeyboard;
           break;
        }
    }
}   


How about using -[UIApplication beginIgnoringInteractionEvents]?

Also, another trick to get the view containing the keyboard is to initialize a dummy view with CGRectZero and set it as the inputAccessoryView of your UITextField or UITextView. Then, get its superview. Still, such shenanigans is private/undocumented, but I've heard of apps doing that and getting accepted anyhow. I mean, how else would Instagram be able to make their comment keyboard interactive (dismiss on swipe) like the Messages keyboard?


I found that developerdoug's answer wasn't working on iOS 7, but by modifying things slightly I managed to get access to what I needed. Here's the code I used:

-(UIView*)findKeyboard
{
    UIView *keyboard = nil;

    for (UIWindow* window in [UIApplication sharedApplication].windows)
    {
        for (UIView *possibleKeyboard in window.subviews)
        {
            if ([[possibleKeyboard description] hasPrefix:@"<UIPeripheralHostView"])
            {
                keyboard = possibleKeyboard;
                break;
            }
        }
    }

    return keyboard;
}

From what I could make out, in iOS 7 the keyboard is composed of a UIPeripheralHostView containing two subviews: a UIKBInputBackdropView (which provides the blur effect on whatever's underneath the keyboard) and a UIKeyboardAutomatic (which provides the character keys). Manipulating the UIPeripheralHostView seems to be equivalent to manipulating the entire keyboard.

Discaimer: I have no idea whether Apple will accept an app that uses this technique, nor whether it will still work in future SDKs.


Be aware, Apple has made it clear that applications which modify private view hierarchies without explicit approval beforehand will be rejected. Take a look in the Apple Developer Forums for various developers' experience on the issue.

If you're just trying to disable the keyboard (prevent it from receiving touches), you might try adding a transparent UIView that is the full size of the screen for the current orientation. If you add it as a subview of the main window, it might work. Apple hasn't made any public method of disabling the keyboard that I'm aware of - you might want to use one of your support incidents with Apple, maybe they will let you in on the solution.


For an app I am currently developing I am using a really quick and easy method:

Add this in the header file:

// Add in interface
UIWindow * _window;

// Add as property
@property (strong, nonatomic) IBOutlet UIView * _keyboard;

Then add this code in the bottom of the keyboardWillShow function:

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

    .... // other keyboard will show code //

    _window = [UIApplication sharedApplication].windows.lastObject;

    [NSTimer scheduledTimerWithTimeInterval:0.05
                                     target:self
                                   selector:@selector(allocateKeyboard)
                                   userInfo:nil
                                    repeats:NO];
}

This code look for when the keyboard is raised and then allocates the current window. I have then added a timer to allocate the keyboard as there were some issues when allocated immediately.

- (void)allocateKeyboard {

    if (!_keyboard) {
        if (_window.subviews.count) {

            // The keyboard is always the 0th subview
            _keyboard = _window.subviews[0];
        }        
    }
}

We now have the keyboard allocated which gives you direct "access" to the keyboard as the question asks.

Hope this helps


Under iOS 8 it appears you have to jump down the chain more than in the past. The following works for me to get the keyboard, although with custom keyboards available and such I wouldn't rely on this working unless you're running in a controlled environment.

- (UIView *)findKeyboard {
    for (UIWindow* window in [UIApplication sharedApplication].windows) {
        UIView *inputSetContainer = [self viewWithPrefix:@"<UIInputSetContainerView" inView:window];
        if (inputSetContainer) {
            UIView *inputSetHost = [self viewWithPrefix:@"<UIInputSetHostView" inView:inputSetContainer];
            if (inputSetHost) {
                UIView *kbinputbackdrop = [self viewWithPrefix:@"<_UIKBCompatInput" inView:inputSetHost];
                if (kbinputbackdrop) {
                    UIView *theKeyboard = [self viewWithPrefix:@"<UIKeyboard" inView:kbinputbackdrop];
                    return theKeyboard;
                }
            }
        }
    }

    return nil;
}


- (UIView *)viewWithPrefix:(NSString *)prefix inView:(UIView *)view {
    for (UIView *subview in view.subviews) {
        if ([[subview description] hasPrefix:prefix]) {
            return subview;
        }
    }

    return nil;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消