18

I want to get rid of the bar on top of the keyboard that appears when you focus a text field in a webview. We have some other ways of handling this and it's redundant and unnecessary.

webview keyboard bar http://beautifulpixel.com/assets/iPhone_Simulator-20100120-152330.png

If you hit this problem, make sure to head over to https://bugreport.apple.com and duplicate rdar://9844216

catlan
  • 25,100
  • 8
  • 67
  • 78
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337

9 Answers9

10
- (void)viewDidLoad {
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}

- (void)keyboardWillShow:(NSNotification *)notification {
    [self performSelector:@selector(removeBar) withObject:nil afterDelay:0];
}

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

    for (UIView *possibleFormView in [keyboardWindow subviews]) {
        // iOS 5 sticks the UIWebFormView inside a UIPeripheralHostView.
        if ([[possibleFormView description] rangeOfString:@"UIPeripheralHostView"].location != NSNotFound) {
            for (UIView *subviewWhichIsPossibleFormView in [possibleFormView subviews]) {
                if ([[subviewWhichIsPossibleFormView description] rangeOfString:@"UIWebFormAccessory"].location != NSNotFound) {
                    [subviewWhichIsPossibleFormView removeFromSuperview];
                }
            }
        }
    }
}

This works well.

url: http://ios-blog.co.uk/iphone-development-tutorials/rich-text-editor-inserting-images-part-6/

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
yun
  • 101
  • 1
  • 2
  • 1
    it did hide the bar, but it left an empty area there. How did you fix it? – jAckOdE May 02 '12 at 09:03
  • 1
    Thanks. But this code doesn't work with UIWebView. Blank space at the buttom of page appears. – Dmitry Aug 09 '12 at 09:21
  • but in here what is the use of this `for (UIView *possibleFormView in [keyboardWindow subviews])` – Anbu.Karthik Feb 10 '17 at 12:05
  • This approach now causes your app to crash in iOS 11 after a few seconds. iOS11 seems to not like the removal of the UIWebFormAccessary from the super view. Has anyone found a workaround? – Sachin Rekhi Sep 23 '17 at 17:46
5

This is an addition to Yun's answer. On iOS6 (6.0.1) there might be a horizontal grey border or shadow line on top of the row where the accessory (previous / next / done) used to be before it was removed. This fix works for me, and I'd like to share. Curious to hear if it works for you as well.

To remove the border, I added this code to the inner loop of removeBar():

if ([[subviewWhichIsPossibleFormView description] rangeOfString:@"UIImageView"].location != NSNotFound) {
    [[subviewWhichIsPossibleFormView layer] setOpacity: 0.0];
}

We need to add the QuartzCore framework to the head of the .m file, so we can set the opacity of the layer involved.

So, we get:

...

#import <QuartzCore/QuartzCore.h>

...

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

    for (UIView *possibleFormView in [keyboardWindow subviews]) {
        // iOS 5 sticks the UIWebFormView inside a UIPeripheralHostView.
        if ([[possibleFormView description] rangeOfString:@"UIPeripheralHostView"].location != NSNotFound) {
            for (UIView *subviewWhichIsPossibleFormView in [possibleFormView subviews]) {
                if ([[subviewWhichIsPossibleFormView description] rangeOfString:@"UIWebFormAccessory"].location != NSNotFound) {
                    [subviewWhichIsPossibleFormView removeFromSuperview];
                }
                // iOS 6 leaves a grey border / shadow above the hidden accessory row
                if ([[subviewWhichIsPossibleFormView description] rangeOfString:@"UIImageView"].location != NSNotFound) {
                    // we need to add the QuartzCore framework for the next line
                    [[subviewWhichIsPossibleFormView layer] setOpacity: 0.0];
                }
            }
        }
    }
}
Remco Nijhuis
  • 134
  • 1
  • 3
  • Perfect! Thanks so much that little thin line was driving me nuts! – Karoh Feb 12 '13 at 01:08
  • Thanks - got rid of that grey line. – Peter Todd Feb 14 '13 at 11:26
  • Oddly enough, after long pressing and using the magnifying glass selection tool, hiding the keyboard, and then showing the keyboard again, the form assist returns and will not be removed again! Taking a closer look indicates that no more keyboardWindow subviews exist after the selection tools was used. A potential solution might be to reset the views somehow though I'm not sure how that can be accomplished. – Karoh Aug 12 '13 at 19:34
4

It looks like there is a very simple way, but I'm pretty sure it will not pass the App Store review. Maybe someone has a clever idea? ;)

@interface UIWebBrowserView : UIView
@end

@interface UIWebBrowserView (UIWebBrowserView_Additions)
@end

@implementation UIWebBrowserView (UIWebBrowserView_Additions)

- (id)inputAccessoryView {
    return nil;
}

@end
Holtwick
  • 1,849
  • 23
  • 29
3

There are no public APIs for doing this. You could remove it by examining the view hierarchy and removing the view as some have suggested, but this would be very risky.

Here's why it's a bad idea:

If Apple doesn't have an official API for removing the bar, they may have good reasons for doing so, and their own code may rely on it being there. You might not ever encounter a problem because you do all your testing (for example) on an English keyboard. But what if the view you are removing is required for entry in another language, or for accessibility purposes? Or what if in a future version of iOS their own implementation changes such that it assumes the view is always there? Your code will crash, and you'll be stuck scrambling to get an update out while frustrated users wait for weeks.

Interestingly, Remco's appended answer proves this point. On iOS 6.0.1, a change was made that required a fix to the hack. Anyone who had implemented the hack for ios 5 would have been forced to do an update as a result. Fortunately it was only an aesthetic change, but it could have been much worse.

Chris Garrett
  • 4,824
  • 1
  • 34
  • 49
1

check out this one. https://gist.github.com/2048571. It works in iOS 5 and later, doesnt work for earlier versions.

jAckOdE
  • 2,402
  • 8
  • 37
  • 67
1

this code definetly works for me... hope this also works for you.

- (void)viewDidLoad{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}


-(void)viewWillAppear:(BOOL)animated{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}

- (void)keyboardWillShow:(NSNotification *)notification {
    [self performSelector:@selector(removeBar) withObject:nil afterDelay:0];
}

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

    // Locate UIWebFormView
    for (UIView *possibleFormView in [keyboardWindow subviews]) {
        if ([[possibleFormView description] hasPrefix:@"<UIPeripheralHostView"]) {
            for (UIView* peripheralView in [possibleFormView subviews]) {

                // hides the backdrop (iOS 7)
                if ([[peripheralView description] hasPrefix:@"<UIKBInputBackdropView"]) {
                    //skip the keyboard background....hide only the toolbar background
                    if ([peripheralView frame].origin.y == 0){
                        [[peripheralView layer] setOpacity:0.0];
                    }
                }
                // hides the accessory bar
                if ([[peripheralView description] hasPrefix:@"<UIWebFormAccessory"]) {
                    // remove the extra scroll space for the form accessory bar
                    UIScrollView *webScroll;
                    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 5.0) {
                        webScroll = [[self webviewpot] scrollView];
                    } else {
                        webScroll = [[[self webviewpot] subviews] lastObject];
                    }
                    CGRect newFrame = webScroll.frame;
                    newFrame.size.height += peripheralView.frame.size.height;
                    webScroll.frame = newFrame;

                    // remove the form accessory bar
                    [peripheralView removeFromSuperview];
                }
                // hides the thin grey line used to adorn the bar (iOS 6)
                if ([[peripheralView description] hasPrefix:@"<UIImageView"]) {
                    [[peripheralView layer] setOpacity:0.0];
                }
            }
        }
    }
}
Infinite Recursion
  • 6,511
  • 28
  • 39
  • 51
Pratik Patel
  • 167
  • 1
  • 2
  • 6
1

I was thinking of intercepting the UIKeyboardWillAppear notification, and giving it to a hidden text field instead, and forwarding the events through javascript to the real one in the webview. But it seems hairy. Things cursor movement and selection would then suck.

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
0

Not easily. You could try to go poking around the subviews in the web view but it would be taboo with Apple.

How about not putting the text field in the web page on the web side, and adding your textfield/textview to the webview explicitly so it doesn't show the nav bar at all, and you can add your own from scratch?

David Sowsy
  • 1,680
  • 14
  • 13
0
[[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWasShown:)

                                             name:UIKeyboardDidShowNotification object:nil];
-(void)keyboardWasShown:(NSNotification*)aNotification
{
UIWindow* tempWindow;

    //Because we cant get access to the UIKeyboard throught the SDK we will just use UIView.
    //UIKeyboard is a subclass of UIView anyways
    UIView* keyboard;

    //Check each window in our application
    for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
    {
            //Get a reference of the current window
            tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];

            //Get a reference of the current view
            for(int i = 0; i < [tempWindow.subviews count]; i++)
            {
                    keyboard = [tempWindow.subviews objectAtIndex:i];

                    if([[keyboard description] hasPrefix:@"<UIPeripheralHostView"] == YES)
                    {      
            keyboard.hidden = YES;
            UIView* keyboardLayer;
            for(int n = 0; n < [keyboard.subviews count]; n++)
            {
                keyboardLayer = [keyboard.subviews objectAtIndex:n];
                NSLog(@" keyboardLayer ::: %@ " ,keyboardLayer);
                if([[keyboardLayer description] hasPrefix:@"<UIWebFormAccessory"] == YES)
                {
                    [keyboardLayer removeFromSuperview ];
                }
            }
            keyboard.hidden = NO;

                    }
            }
    }

 NSLog(@"keyboardWasShown" );

}

check this as well: http://pastebin.com/s3Fkxvsk

Emile Khattar
  • 369
  • 4
  • 7