Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 7 UIWebView keyboard issue

I have to remove this bar as here link but for iOS 7 this code does not work.

like image 587
Matrosov Oleksandr Avatar asked Sep 26 '13 16:09

Matrosov Oleksandr


2 Answers

We remove this bar with some Objective C runtime trickery.

We have a class which has one method:

@interface _SwizzleHelper : NSObject @end

@implementation _SwizzleHelper

    -(id)inputAccessoryView
    {
        return nil;
    }

@end

Once we have a web view which we want to remove the bar from, we iterate its scroll view's subviews and take the UIWebDocumentView class. We then dynamically make the superclass of the class we created above to be the subview's class (UIWebDocumentView - but we cannot say that upfront because this is private API), and replace the subview's class to our class.

#import "objc/runtime.h"    

-(void)__removeInputAccessoryView
{
    UIView* subview;

    for (UIView* view in self.scrollView.subviews) {
        if([[view.class description] hasPrefix:@"UIWeb"])
            subview = view;
    }

    if(subview == nil) return;

    NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelper", subview.class.superclass];
    Class newClass = NSClassFromString(name);

    if(newClass == nil)
    {
        newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0);
        if(!newClass) return;

        Method method = class_getInstanceMethod([_SwizzleHelper class], @selector(inputAccessoryView));
        class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method));

        objc_registerClassPair(newClass);
    }

    object_setClass(subview, newClass);
}

The equivalent of the above in Swift 3.0:

import UIKit
import ObjectiveC

var swizzledClassMapping = [AnyClass]()

extension UIWebView {
    func noInputAccessoryView() -> UIView? {
        return nil
    }

    public func removeInputAccessoryView() {
        var subview: AnyObject?

        for (_, view) in scrollView.subviews.enumerated() {
            if NSStringFromClass(type(of: view)).hasPrefix("UIWeb") {
                subview = view
            }
        }

        guard subview != nil else {
            return
        }

        //Guard in case this method is called twice on the same webview.
        guard !(swizzledClassMapping as NSArray).contains(type(of: subview!)) else {
            return;
        }

        let className = "\type(of: subview!)_SwizzleHelper"
        var newClass : AnyClass? = NSClassFromString(className)

        if newClass == nil {
            newClass = objc_allocateClassPair(type(of: subview!), className, 0)

            guard newClass != nil else {
                return;
            }

            let method = class_getInstanceMethod(type(of: self), #selector(UIWebView.noInputAccessoryView))
            class_addMethod(newClass!, #selector(getter: UIResponder.inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method))

            objc_registerClassPair(newClass!)

            swizzledClassMapping += [newClass!]
        }

        object_setClass(subview!, newClass!)
    }
}
like image 101
Léo Natan Avatar answered Oct 18 '22 09:10

Léo Natan


I've made a cocoapod based on this blog post from @bjhomer.

You can replace the inputaccessoryview and not just hide it. I hope this will help people with the same issue.

https://github.com/lauracpierre/FA_InputAccessoryViewWebView

You can find the cocoapod page right here.

like image 32
Pierre Avatar answered Oct 18 '22 09:10

Pierre