在 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。按预期工作。希望对你有帮助。
仅供参考:我检查了文档,它没有提到 not 将WKWebView
子类化,因此允许子类化。
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 附件栏的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Swift 3 的 WKWebView 中注入 javascript
如何在swift 4中从WKWebView中的网页中删除DIV标签?
关于在 Swift 中删除 WKWebView 中的 UIMenuController 默认 menuItems 的问题