2

I am using a WKWebView in my Swift app to present some textfields.

I set some appearance properties to match a specific design, in this case its background has to be blue. But when the keyboard is triggered by the WKWebView, it does something with the appearance properties and shows the keyboard toolbar in a pale light appearance of my color, do you know why?

The only appearance manipulation on UIToolBar that somewhat worked is this one:

    UIToolbar.appearance().backgroundColor = .blue

This is my problem: Pale thing

This is my goal: Goal keyboard

Viktor_DE
  • 276
  • 3
  • 19
  • 1
    https://stackoverflow.com/questions/48978134/modifying-keyboard-toolbar-accessory-view-with-wkwebview – kkiermasz Aug 14 '18 at 08:33
  • Possible duplicate of [Modifying keyboard toolbar / accessory view with WKWebView](https://stackoverflow.com/questions/48978134/modifying-keyboard-toolbar-accessory-view-with-wkwebview) – Enea Dume Aug 14 '18 at 08:34
  • Thank you for your comments, I will check them out, and if it's relevant for the result, I will mark your comment as answer. If duplicate, I'll just delete the question. – Viktor_DE Aug 14 '18 at 08:53
  • Thank you, the referenced question was interesting, but it is not affecting my question. So I am still looking for how to solve this. – Viktor_DE Aug 14 '18 at 13:39
  • has someone found a solution? – Delorean Oct 03 '18 at 13:31
  • No, sorry. I had to keep that and build my page to match that bluish color. – Viktor_DE Oct 04 '18 at 14:24

2 Answers2

5

Found a way, ended up to swizzle UIToolbars. Hopefully everything is there, but you would get an idea. Swift 4:

class YourController: UIViewController {

    @IBOutlet weak var webView: PWebView!
    var toolbar : UIToolbar?

    func viewDidLoad() {
        webView.addInputAccessoryView(toolbar: self.getToolbar(height: 44))
    }

    func getToolbar(height: Int) -> UIToolbar? {
        let toolBar = UIToolbar()
        toolBar.frame = CGRect(x: 0, y: 50, width: 320, height: height)
        toolBar.barStyle = .black
        toolBar.tintColor = .white
        toolBar.barTintColor = UIColor.blue

        let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(onToolbarDoneClick(sender:)) )
        let flexibleSpaceItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil )

        toolBar.setItems([flexibleSpaceItem, doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true

        toolBar.sizeToFit()
        return toolBar
    }

    @objc func onToolbarDoneClick(sender: UIBarButtonItem) {
        webView?.resignFirstResponder()
    }
}


var ToolbarHandle: UInt8 = 0

extension WKWebView {

    func addInputAccessoryView(toolbar: UIView?) {
        guard let toolbar = toolbar else {return}
        objc_setAssociatedObject(self, &ToolbarHandle, toolbar, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)

        var candidateView: UIView? = nil
        for view in self.scrollView.subviews {
            let description : String = String(describing: type(of: view))
            if description.hasPrefix("WKContent") {
                candidateView = view
                break
            }
        }
        guard let targetView = candidateView else {return}
        let newClass: AnyClass? = classWithCustomAccessoryView(targetView: targetView)

        guard let targetNewClass = newClass else {return}

        object_setClass(targetView, targetNewClass)
    }

    func classWithCustomAccessoryView(targetView: UIView) -> AnyClass? {
        guard let _ = targetView.superclass else {return nil}
        let customInputAccesoryViewClassName = "_CustomInputAccessoryView"             

        var newClass: AnyClass? = NSClassFromString(customInputAccesoryViewClassName)
        if newClass == nil {
            newClass = objc_allocateClassPair(object_getClass(targetView), customInputAccesoryViewClassName, 0)
        } else {
            return newClass
        }

        let newMethod = class_getInstanceMethod(WKWebView.self, #selector(WKWebView.getCustomInputAccessoryView))
        class_addMethod(newClass.self, #selector(getter: WKWebView.inputAccessoryView), method_getImplementation(newMethod!), method_getTypeEncoding(newMethod!))

        objc_registerClassPair(newClass!)

        return newClass
    }

    @objc func getCustomInputAccessoryView() -> UIView? {
        var superWebView: UIView? = self
        while (superWebView != nil) && !(superWebView is WKWebView) {
            superWebView = superWebView?.superview
        }

        guard let webView = superWebView else {return nil}

        let customInputAccessory = objc_getAssociatedObject(webView, &ToolbarHandle)
        return customInputAccessory as? UIView
    }
}
Delorean
  • 356
  • 3
  • 11
0
private var keyBordView: UIView?


override func viewDidLoad() {
    super.viewDidLoad()


    let webView = WKWebView.init(frame: view.bounds)
    webView.loadHTMLString("<html><body><div contenteditable='true'></div></body></html>", baseURL: nil)
    view.addSubview(webView)
    for subview in webView.scrollView.subviews {
        if subview.classForCoder.description() == "WKContentView" {
            keyBordView = subview
        }
    }

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: .UIKeyboardDidShow, object: nil)

    // Do any additional setup after loading the view.
}


@objc private func keyboardShow() {

    let keyboardToolbar = UIToolbar()
    keyboardToolbar.backgroundColor = UIColor.blue
    keyboardToolbar.sizeToFit()
    let flexBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    let doneBarButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.dismissKeyBord))
    keyboardToolbar.items = [flexBarButton, doneBarButton]
    keyBordView = keyboardToolbar
}
Mahesh Dangar
  • 806
  • 5
  • 11