在 Swift 中删除 WKWebView 附件栏

Posted

技术标签:

【中文标题】在 Swift 中删除 WKWebView 附件栏【英文标题】:Removing WKWebView Accesory bar in Swift 【发布时间】:2015-11-22 10:47:15 【问题描述】:

我现在正在尝试几天将this 转换为 Swift,但实际上并没有太多的背景知识。

这是我到目前为止所得到的......而且我一直在寻找谷歌,但并不知道要搜索什么才能更具体。你能解释一下我做错了什么吗?谢谢

更新

我添加了objective-c标签,以便更多与此线程相关的人能够看到它并希望得到答案。

【问题讨论】:

请问您是如何详细解决这个问题的? 【参考方案1】:

对于仍在寻找的人,WebKit 团队更新了WKWebView (ios 13+),以便您可以对其进行子类化以删除/更新输入附件视图:

https://trac.webkit.org/changeset/246229/webkit#file1

在 Swift 中,我对它进行了子类化,并返回 nil。按预期工作。希望对你有帮助。

仅供参考:我检查了文档,它没有提到 notWKWebView 子类化,因此允许子类化。

import WebKit

class RichEditorWebView: WKWebView 

    var accessoryView: UIView?

    override var inputAccessoryView: UIView? 
        // remove/replace the default accessory view
        return accessoryView
    


你可以在这里找到它的工作版本:https://github.com/cbess/RichEditorView/commits/master

【讨论】:

非常感谢您将 RichEditorView 移植到 WKWebView... 为我节省了大量时间!!! 太棒了。每当我点击 webview 中的文本输入时,我的应用程序就会崩溃。事实证明,问题与尝试显示附件栏有关。在这种情况下,附件栏看起来像一个向上箭头、一个向下箭头和“完成”一词,试图帮助用户浏览表单。这个解决方案阻止了我的应用程序崩溃。【参考方案2】:

Michael Dautermann 的回答一切正常,但为了隐藏附件栏,您需要将 UIView 类的 inputAccessoryView() 方法与 _NoInputAccessoryView 类的 inputAccessoryView() 混合。我刚刚在代码中添加了几行额外的代码来完成这项方法调配工作。

首先你需要一个假类来交换

final class FauxBarHelper: NSObject 
    var inputAccessoryView: AnyObject?  return nil 

然后在你的控制器类中创建这个方法

/// Removes the keyboard accessory view from the web view
/// Source: http://***.com/a/32620344/308315 / http://***.com/a/33939584/308315
func _removeInputAccessoryView(webView: UIWebView) 
    var targetView: UIView? = nil

    for view in webView.scrollView.subviews 
        if String(describing: type(of: view)).hasPrefix("WKContent") 
            targetView = view
        
    

    guard let target = targetView else  return 

    let noInputAccessoryViewClassName = "\(target.superclass!)_NoInputAccessoryView"
    var newClass: AnyClass? = NSClassFromString(noInputAccessoryViewClassName)
    if newClass == nil 
        let targetClass: AnyClass = object_getClass(target)
        newClass = objc_allocateClassPair(targetClass, noInputAccessoryViewClassName.cString(using: String.Encoding.ascii)!, 0)
    

    let originalMethod = class_getInstanceMethod(FauxBarHelper.self, #selector(getter: FauxBarHelper.inputAccessoryView))
    class_addMethod(newClass!.self, #selector(getter: FauxBarHelper.inputAccessoryView), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
    object_setClass(target, newClass)

HTH ;)

【讨论】:

@socca1157 感谢您的建议,我会尝试在 Medium 上写一篇,我会及时通知您:) @iWasRobbed 感谢更新 Swift 3 的答案。 这有什么更新吗?似乎无法让它运行最新版本的 Swift 和 iOS。 小提示:我在使用听写时遇到了这种方法的问题。来自UIDictationController 的奇怪崩溃。 newClass 对 Obj-C 不可见,在 objc_allocateClassPair(…) 调用之后添加 objc_registerClassPair(newClass) 似乎可以解决问题。 像@eeeee 一样,我在使用上述代码和语音听写时观察到崩溃。我建议按照他的建议进行更改。【参考方案3】:

这是一个更安全(没有不安全的展开)版本,适用于 Swift 4 和(至少)iOS 9 低谷 12。

fileprivate final class InputAccessoryHackHelper: NSObject 
    @objc var inputAccessoryView: AnyObject?  return nil 


extension WKWebView 
    func hack_removeInputAccessory() 
        guard let target = scrollView.subviews.first(where: 
            String(describing: type(of: $0)).hasPrefix("WKContent")
        ), let superclass = target.superclass else 
            return
        

        let noInputAccessoryViewClassName = "\(superclass)_NoInputAccessoryView"
        var newClass: AnyClass? = NSClassFromString(noInputAccessoryViewClassName)

        if newClass == nil, let targetClass = object_getClass(target), let classNameCString = noInputAccessoryViewClassName.cString(using: .ascii) 
            newClass = objc_allocateClassPair(targetClass, classNameCString, 0)

            if let newClass = newClass 
                objc_registerClassPair(newClass)
            
        

        guard let noInputAccessoryClass = newClass, let originalMethod = class_getInstanceMethod(InputAccessoryHackHelper.self, #selector(getter: InputAccessoryHackHelper.inputAccessoryView)) else 
            return
        
        class_addMethod(noInputAccessoryClass.self, #selector(getter: InputAccessoryHackHelper.inputAccessoryView), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
        object_setClass(target, noInputAccessoryClass)
    

【讨论】:

像魅力一样工作。谢谢。 何时何地调用这个? @JamshedAlam 几乎可以在任何地方,当您需要时,我会在设置其他属性(tintColor 等)时这样做【参考方案4】:

这段代码 sn-p 应该可以帮助您解决问题:

class _NoInputAccessoryView: NSObject 

    func removeInputAccessoryViewFromWKWebView(webView: WKWebView) 
        // make sure to make UIView an optional here...
        var targetView: UIView? = nil
        for view in webView.scrollView.subviews 
            if String(view.dynamicType).hasPrefix("WKContent") 
                targetView = view
            
        

        // only optionals can be nil
        if targetView == nil 
            return
        

        let noInputAccessoryViewClassName = "\(targetView!.superclass)_NoInputAccessoryView"
        var newClass : AnyObject? = NSClassFromString(noInputAccessoryViewClassName)
        if newClass == nil 
            let uiViewClass : AnyClass = object_getClass(targetView!)
            newClass = objc_allocateClassPair(uiViewClass, noInputAccessoryViewClassName.cStringUsingEncoding(NSASCIIStringEncoding)!, 0)
        
     

您还可以使用“String(view.dynamicType)”来获取您正在查看的对象的类名as I noticed via this answer as I was researching the way to solve your problem。

像这样在 Objective-C 和 Swift 中使用 hasPrefix 真的很hacky,也许可以为生产代码找到更好的隐藏键盘的方法?

【讨论】:

我已经完成了更改和一个小修复,我用它编辑了你的帖子,但现在我得到了this。我已经尝试添加 newClass: AnyClass? = NSClassFromString 来解决警告和 newClass == nil 比较,但它给我留下了第三个错误,Cannot convert value of type UIView to expected type AnyClass! 我已经对我的代码进行了调整...现在试试看。 还有一个愚蠢的问题,我如何将这个类应用到 webview 对象之上?我只是新手和愚蠢..对不起 这不是一个愚蠢的问题,你也不是。如果您查看您要移植的原始 Objective-C 源代码,作者将他的“removeInputAccessoryViewFromWKWebView”函数作为视图控制器的一部分。你是作为一个从 NSObject 派生的独立类来做你的。假设您从纯 Swift 视图控制器调用它,您需要执行类似“let navHelper = _NoInputAccessoryView.init()”和“navHelper. removeInputAccessoryViewFromWKWebView(passInWebViewHere)”的操作。有意义吗? 另外,您确实应该将该类的名称从“_NoInputAccessoryView”更改为不以下划线开头的名称(通常为实例变量保留的样式)。跨度>

以上是关于在 Swift 中删除 WKWebView 附件栏的主要内容,如果未能解决你的问题,请参考以下文章

如何编辑从 WKWebView 显示的键盘附件视图?

如何在 Swift 3 的 WKWebView 中注入 javascript

如何在swift 4中从WKWebView中的网页中删除DIV标签?

关于在 Swift 中删除 WKWebView 中的 UIMenuController 默认 menuItems 的问题

iOS WKWebView 加载进度条导航栏返回&关闭 (Swift 4)

iOS WKWebView 状态栏填充