Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom webview keyboard issues

So adapting code form this thread UIKeyboardAppearance in UIWebView and TomSwift's awesome answer, I got about 99% of it working.

In the iOS 7 simulator, everything appears to work just fine. However in iOS 8, when the keyboard first appears, the < > Done bar is white. When I tap or select another input, it changes to my specified color.

My question is, how can I prevent and or change that white portion?

White BarDark Bar

All code in the other thread is identical, except for my color which I call like so in the keyboardWillAppear.

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 : @"<UIInputSetContainerView"]) {

        for (UIView* peripheralView in possibleFormView.subviews) {
            peripheralView.backgroundColor = [UIColor colorWithRed:0.271 green:0.271 blue:0.271 alpha:0.75];

            for (UIView* peripheralView_sub in peripheralView.subviews) {
                peripheralView_sub.backgroundColor = [UIColor colorWithRed:0.271 green:0.271 blue:0.271 alpha:0.75];

            }
        }
    }
}

Any help would be greatly appreciated.

like image 268
ChrisOSX Avatar asked Feb 23 '15 00:02

ChrisOSX


3 Answers

So with iOS 9+ out, I found it broke the mentioned methods. But with some tinkering and looking through some views, I came up with an addition to what i've already answered below.

Now I've decided to ditch the custom color stuff, I'm digging just the black keyboard, suits my app. Anyways, here's what works for me. Tested on 9.1 sim to 7. Also on my 6+ running 9.0.2.

//Keyboard setting
@interface UIWebBrowserView : UIView
@end
@interface UIWebBrowserView (UIWebBrowserView_Additions)
@end
@implementation UIWebBrowserView (UIWebBrowserView_Additions)
- (id)inputAccessoryView {
    return nil;
}

- (UIKeyboardAppearance) keyboardAppearance{

    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    BOOL switchOn = [userDefaults boolForKey:@"darkKeyboard"];

    if (switchOn) {
        return UIKeyboardAppearanceDark;
    }
    else {
        return UIKeyboardAppearanceDefault;
    }
}
@end

@interface UITextInputTraits : UIWebBrowserView
@end
@interface UITextInputTraits (UIWebBrowserView)
@end
@implementation UITextInputTraits (UIWebBrowserView)
- (UIKeyboardAppearance) keyboardAppearance{

    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    BOOL switchOn = [userDefaults boolForKey:@"darkKeyboard"];

    if (switchOn) {
        return UIKeyboardAppearanceDark;
    }
    else {
        return UIKeyboardAppearanceDefault;
    }
}
@end

I really hope somebody finds these answers helpful :D

UPDATED INFO: Was curious about the done bar, which is how this all got started. I re-enabled it just to see, and to find out it changed it to black. Nice bonus, although I've ditched it to hide the keyboard with scroll.

UPDATE 12/19/15 So I decided to make my transition from UIWebView to WKWebView, only to find out that obviously things are different between the two. I've managed to get it working again. Regular UIKeyboardAppearanceDark calls causes the keyboard to be more transparent than I like. So I modified it to my liking. Again, probably not the standard way of doing things, but I don't care, it's not going to apple anyways.

Everything is still being put in the AppDelegate.

//Removing the input bar above the keyboard.
@interface InputHider : NSObject @end
@implementation InputHider
-(id)inputAccessoryView{
    return nil;
}
@end

@interface UIWebBrowserView : NSObject
@end
@interface NSObject (UIWebBrowserView_Additions)
@end
@implementation NSObject (UIWebBrowserView_Additions)
- (UIKeyboardAppearance) keyboardAppearance{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    BOOL switchOn = [userDefaults boolForKey:@"darkKeyboard"];

    if (switchOn) {
        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 isKindOfClass:NSClassFromString(@"UIInputSetContainerView")] ||
                [possibleFormView isKindOfClass:NSClassFromString(@"UIInputSetHostView")]) {
                for (UIView* peripheralView in possibleFormView.subviews) {
                    peripheralView.backgroundColor = [UIColor colorWithRed:0.271 green:0.271 blue:0.271 alpha:1.0];

                    //Keyboard background
                    for (UIView* peripheralView_sub in peripheralView.subviews) {
                        peripheralView_sub.backgroundColor = [UIColor colorWithRed:0.271 green:0.271 blue:0.271 alpha:1.0];

                        //Accessory bar color
                        if ([possibleFormView isKindOfClass:NSClassFromString(@"WKContentView")]) {
                            for (UIView* UIInputViewContent_sub in peripheralView_sub.subviews) {
                                [[UIInputViewContent_sub layer] setOpacity : 1.0];
                                UIInputViewContent_sub.backgroundColor = [UIColor colorWithRed:0.271 green:0.271 blue:0.271 alpha:1.0];

                            }
                        }
                    }
                }
            }
        }
        return UIKeyboardAppearanceDark;
    }
    else {
        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 isKindOfClass:NSClassFromString(@"UIInputSetContainerView")] || [possibleFormView isKindOfClass:NSClassFromString(@"UIKeyboard")]) {
                for (UIView* peripheralView in possibleFormView.subviews) {
                    peripheralView.backgroundColor = [UIColor clearColor];

                    //Keyboard background
                    for (UIView* peripheralView_sub in peripheralView.subviews) {
                        peripheralView_sub.backgroundColor = [UIColor clearColor];

                        //Accessory bar color
                        if ([possibleFormView isKindOfClass:NSClassFromString(@"UIWebFormAccessory")]) {
                            for (UIView* UIInputViewContent_sub in peripheralView_sub.subviews) {
                                [[UIInputViewContent_sub layer] setOpacity : 1.0];
                                UIInputViewContent_sub.backgroundColor = [UIColor clearColor];

                            }
                        }
                    }
                }
            }
        }
        return UIKeyboardAppearanceDefault;
    }
}
@end

@interface UITextInputTraits : UIWebBrowserView
@end
@interface UITextInputTraits (UIWebBrowserView)
@end
@implementation UITextInputTraits (UIWebBrowserView)
- (UIKeyboardAppearance) keyboardAppearance{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    BOOL switchOn = [userDefaults boolForKey:@"darkKeyboard"];

    if (switchOn) {
        return UIKeyboardAppearanceDark;
    }
    else {
        return UIKeyboardAppearanceDefault;
    }
}
@end

//Disables endDisablingInterfaceAutorotationAnimated error for keyboard
@interface UIWindow (UIWebBrowserView)
- (void)beginDisablingInterfaceAutorotation;
- (void)endDisablingInterfaceAutorotation;
@end

@implementation UIWindow (UIWebBrowserView)
- (void)beginDisablingInterfaceAutorotation {}
- (void)endDisablingInterfaceAutorotation{}
@end

I haven't managed to find a way to hide the inputAccessoryBar like I did before, but thanks to a couple threads I got it working. In my view controllers I call:

-(void)removeInputAccessoryView {
    UIView* subview;

    for (UIView* view in webView.scrollView.subviews) {
        if([[view.class description] hasPrefix:@"WKContent"])
            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([AppDelegate class], @selector(inputAccessoryView));
        class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method));

        objc_registerClassPair(newClass);
    }

    object_setClass(subview, newClass);
}

And in the viewDidLoad I call:

[self removeInputAccessoryView];

I plan on tinkering around some more, but for now, this works to what I need it to do.

like image 179
ChrisOSX Avatar answered Nov 14 '22 19:11

ChrisOSX


WKWebView Keyboard

Here is a solution for WKWebView's that uses swizzling, and is fairly easy to incorporate and works on iOS 9, 10 & 11. Just create a new class called WKKeyboard and add the following code:

WKKeyboard.h

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WKKeyboard : NSObject

+ (void)setStyle:(UIKeyboardAppearance)style on:(WKWebView *)webView;

@end

WKKeyboard.m

#import "WKKeyboard.h"
#import <objc/runtime.h>

@implementation WKKeyboard

// Allows the changing of keyboard styles
static UIKeyboardAppearance keyboardStyle;

// Leave this as an instance method
- (UIKeyboardAppearance)keyboardAppearance {
    return keyboardStyle;
}

// This can be a class method
+ (void)setStyle:(UIKeyboardAppearance)style on:(WKWebView *)webView {
    for (UIView *view in [[webView scrollView] subviews]) {
        if([[view.class description] containsString:@"WKContent"]) {
            UIView *content = view;
            NSString *className = [NSString stringWithFormat:@"%@_%@",[[content class] superclass],[self class]];
            Class newClass = NSClassFromString(className);
            if (!newClass) {
              newClass = objc_allocateClassPair([content class], [className cStringUsingEncoding:NSASCIIStringEncoding], 0);
              Method method = class_getInstanceMethod([WKKeyboard class], @selector(keyboardAppearance));
              class_addMethod(newClass, @selector(keyboardAppearance), method_getImplementation(method), method_getTypeEncoding(method));
              objc_registerClassPair(newClass);
            }
            object_setClass(content, newClass);
            keyboardStyle = style;
            return;
        }
    }
}

@end

Usage

// The WKWebView you want to change the keyboard on
WKWebView *webView = [WKWebView alloc] init];

// Then just call the class method with the style and webview
[WKKeyboard setStyle:UIKeyboardAppearanceDark on:webView];

Hope this helps someone, this way you can selectively change the appearance on a single WKWebView and not all of them!

like image 37
Asleepace Avatar answered Nov 14 '22 17:11

Asleepace


Swift version of @Asleepace's answer. And It just works out for me. Method swizzling is a way to go here.

class WKKeybaord: NSObject {
static var keyboardStyle: UIKeyboardAppearance = .default

@objc func keyboardAppearance() -> UIKeyboardAppearance {
    return WKKeybaord.keyboardStyle
}

class func setStyle(with style: UIKeyboardAppearance, on webView: WKWebView) {
    for view in webView.scrollView.subviews {
        if view.self.description.contains("WKContent") {
            let content = view
            var className: String? = nil
            if let superclass = content.self.superclass {
                className = "\(superclass)_\(type(of: self))"
            }
            var newClass: AnyClass? = NSClassFromString(className ?? "")
            if newClass == nil {
                newClass = objc_allocateClassPair(object_getClass(content), className ?? "", 0)
                if let method = class_getInstanceMethod(WKKeybaord.self, #selector(self.keyboardAppearance)) {
                    class_addMethod(newClass, #selector(self.keyboardAppearance), method_getImplementation(method), method_getTypeEncoding(method))
                    objc_registerClassPair(newClass!)
                }
            }
            object_setClass(content, newClass!)
            keyboardStyle = style
            return
        }
    }
}
}
like image 33
EI Captain v2.0 Avatar answered Nov 14 '22 19:11

EI Captain v2.0