Skip to content
Create a gist now

Instantly share code, notes, and snippets.

Hiding the inputAccessoryView of a UIWebView
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
@interface UIWebView (HackishAccessoryHiding)
@property (nonatomic, assign) BOOL hackishlyHidesInputAccessoryView;
@end
@implementation UIWebView (HackishAccessoryHiding)
static const char * const hackishFixClassName = "UIWebBrowserViewMinusAccessoryView";
static Class hackishFixClass = Nil;
- (UIView *)hackishlyFoundBrowserView {
UIScrollView *scrollView = self.scrollView;
UIView *browserView = nil;
for (UIView *subview in scrollView.subviews) {
if ([NSStringFromClass([subview class]) hasPrefix:@"UIWebBrowserView"]) {
browserView = subview;
break;
}
}
return browserView;
}
- (id)methodReturningNil {
return nil;
}
- (void)ensureHackishSubclassExistsOfBrowserViewClass:(Class)browserViewClass {
if (!hackishFixClass) {
newClass = objc_allocateClassPair(browserViewClass, hackishFixClassName, 0);
IMP nilImp = [self methodForSelector:@selector(methodReturningNil)];
class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:");
objc_registerClassPair(newClass);
hackishFixClass = newClass;
}
}
- (BOOL) hackishlyHidesInputAccessoryView {
UIView *browserView = [self hackishlyFoundBrowserView];
return [browserView class] == hackishFixClass;
}
- (void) setHackishlyHidesInputAccessoryView:(BOOL)value {
UIView *browserView = [self hackishlyFoundBrowserView];
if (browserView == nil) {
return;
}
[self ensureHackishSubclassExistsOfBrowserViewClass:[browserView class]];
if (value) {
object_setClass(browserView, hackishFixClass);
}
else {
Class normalClass = objc_getClass("UIWebBrowserView");
object_setClass(browserView, normalClass);
}
[browserView reloadInputViews];
}
@end
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
@interface UIWebView (HackishAccessoryHiding)
@property (nonatomic, assign) BOOL hackishlyHidesInputAccessoryView;
@end
@implementation UIWebView (HackishAccessoryHiding)
static const char * const hackishFixClassName = "UIWebBrowserViewMinusAccessoryView";
static Class hackishFixClass = Nil;
- (UIView *)hackishlyFoundBrowserView {
UIScrollView *scrollView = self.scrollView;
UIView *browserView = nil;
for (UIView *subview in scrollView.subviews) {
if ([NSStringFromClass([subview class]) hasPrefix:@"UIWebBrowserView"]) {
browserView = subview;
break;
}
}
return browserView;
}
- (id)methodReturningNil {
return nil;
}
- (void)ensureHackishSubclassExistsOfBrowserViewClass:(Class)browserViewClass {
if (!hackishFixClass) {
Class newClass = objc_allocateClassPair(browserViewClass, hackishFixClassName, 0);
IMP nilImp = [self methodForSelector:@selector(methodReturningNil)];
class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:");
objc_registerClassPair(newClass);
hackishFixClass = newClass;
}
}
- (BOOL) hackishlyHidesInputAccessoryView {
UIView *browserView = [self hackishlyFoundBrowserView];
return [browserView class] == hackishFixClass;
}
- (void) setHackishlyHidesInputAccessoryView:(BOOL)value {
UIView *browserView = [self hackishlyFoundBrowserView];
if (browserView == nil) {
return;
}
[self ensureHackishSubclassExistsOfBrowserViewClass:[browserView class]];
if (value) {
object_setClass(browserView, hackishFixClass);
}
else {
Class normalClass = objc_getClass("UIWebBrowserView");
object_setClass(browserView, normalClass);
}
[browserView reloadInputViews];
}
@end
@0xced
0xced commented Mar 20, 2012

You have two .m files with almost identical content.

@bjhomer
Owner
bjhomer commented Mar 20, 2012

Hmm. So I do. Not sure how that happened. Will fix.

@bjhomer
Owner
bjhomer commented Mar 20, 2012

Fixed. Thanks for pointing that out.

@ronadams

Just an fyi, this gist crashes in iOS 4.2 because there is no .scrollView property on WebView. I plugged that hole in a super-hacky by replacing hackishlyFoundBrowserView with the following:

  • (UIView *)hackishlyFoundBrowserView {
    UIScrollView *scrollView;

    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 5.0) {
    scrollView = self.scrollView;
    } else {
    scrollView = [self.subviews lastObject]; // iOS 2.x (?) - 4.x
    }

    UIView *browserView = nil;
    for (UIView *subview in scrollView.subviews) {
    if ([NSStringFromClass([subview class]) hasPrefix:@"UIWebBrowserView"]) {
    browserView = subview;
    break;
    }
    }
    return browserView;
    }

@jessep
jessep commented Sep 26, 2012

For anyone who wants to actually use this in your code, you need to do three things:

1) Make setHackishlyHidesInputAccessoryView available to your code (change the interface to):
@interface UIWebView (HackishAccessoryHiding)
@property (nonatomic, assign) BOOL hackishlyHidesInputAccessoryView;
- (void) setHackishlyHidesInputAccessoryView:(BOOL)value;
@end

2) Call that in your code somewhere. For me, I called it after initiating load of a webview as follows:
[self.webView setHackishlyHidesInputAccessoryView:YES];

3) In ensureHackishSubclassExistsOfBrowserViewClass, add 'Class' before the first appearance of the 'newClass' variable. It should now look like:
Class newClass = objc_allocateClassPair(browserViewClass, hackishFixClassName, 0);

And also follow the advice above if you want it to work on iOS 4.x

@bjhomer
Owner
bjhomer commented Sep 26, 2012

@jessep:

  1. There's no need to declare the -setHackishlyHidesInputAccessoryView: method; it's implicitly declared as part of the @property. That's how @propertys work. You can read more about it here: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html
  2. Correct; you just need to call webView.hackishlyHidesInputAccessoryView = YES or [webView setHackishlyHidesInputAccessoryView:YES]. Both are equivalent.
  3. Oh, you're absolutely right, I somehow missed the variable type declaration there. I'll fix that.
@devinfoley

Do you think this will pass AppStore review?

@julientherier

Based on Mike Ash comments http://www.mikeash.com/pyblog/friday-qa-2010-11-6-creating-classes-at-runtime-in-objective-c.html, would it be better to do the following?

Method inputAccessoryView = class_getInstanceMethod([NSResponder class],
                                                 @selector(inputAccessoryView));
const char *types = method_getTypeEncoding(inputAccessoryView);
class_addMethod(newClass, @selector(inputAccessoryView), nilImp, types);

@devinfoley
I think some apps like Evernote, which is probably using a UIWebView to show/edit notes, may use something similar to this Gist.

@matt-curtis

I used a variation of this to get rid of the inputView entirely, nice work.

@waterzhang0423

I seems like does not work on IOS 6.x.

@waterzhang0423

@matt-curtis:

how to get rid of inputView?

@AskeG
AskeG commented Aug 2, 2013

@bjhomer
I'm afraid I'm very inexperienced within Objective-C, I've created a .m file (UIWebViewFormAssistantHack.m) with this contents, and although you explained that the property should be accessible, I can't seem to reference it from the viewDidLoad scope using self.webView.sethackishlyHidesInputAccessoryView(YES); (or self.webView.hackishlyHidesInputAccessoryView = YES for that matter)

Would you be so kind to help me clarify what I am doing wrong?

@matt-curtis

@zhangchuqi
Just replace references to "inputAccessoryView" with "inputView" in the above code. And instead of returning nil (which I think in the case of inputView will still cause the default keyboard to show) you'll want to return an empty UIView.

@AskeG
You probably know this by now, but you need to include the category's .h file in header of your view controller.

@drunkhacker

I think this is way much better than https://github.com/don/KeyboardToolbarRemover

@iospro
iospro commented Jan 26, 2014

You can eliminate [browserView reloadInputViews];

@Schandlich

I didn't see a license on the website. Would you be willing to license the code under the MIT (http://opensource.org/licenses/MIT) or BSD (http://opensource.org/licenses/BSD-2-Clause) license?

@tinhbka
tinhbka commented Jul 15, 2015

hi ! can we custom inputView for UIWebview with this solutions?

@lauracpierre

I've made a Cocoapod based on your solution.

https://cocoapods.org/pods/FA_InputAccessoryViewWebView

@kgaidis
kgaidis commented May 5, 2016

I also posted a gist that allows to customize OR disable the inputAccessoryView:

https://gist.github.com/kgaidis/5f9a8c7063b687cc3946fad6379c1a66

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.