Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Hiding the inputAccessoryView of a UIWebView

View UIWebView+AccessoryHiding.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
#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
View UIWebView+AccessoryHiding.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
#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 commented

You have two .m files with almost identical content.

Owner

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

Owner

Fixed. Thanks for pointing that out.

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;
    }

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

Owner

@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.

Do you think this will pass AppStore review?

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.

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

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

@matt-curtis:

how to get rid of inputView?

@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?

@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.

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

You can eliminate [browserView reloadInputViews];

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?

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.