WKWebView 中的链接随机不可点击
Links in WKWebView randomly not clickable
在我用 Swift 2.1 编写的 iOS 应用程序中,我使用 WKWebView 加载 HTML 字符串,该字符串是使用 JSON 解析器从 wordpress 博客加载的.
我实现了委托方法 func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
并将 WKWebView 的导航委托设置为自身以处理 link 次按下。
现在,当我打开包含 WKWebView 的 ViewController 时,此委托方法被调用一次,这是您在加载 webView 时所期望的行为 - 因此委托似乎设置正确。
我现在的问题是,大多数时候 webView 包含的 link 是 不可点击的 。您通常会期望 灰色背景出现 ,当您按下 link 时,如下图所示。但大多数时候,当我按下 link 时,灰色背景不会出现,所以当我触摸时,委托方法不会被调用。这个问题肯定与 WKNavigationDelegate
的错误配置无关,因为有时 link 选择工作正常(大约 10 %)。
您知道为什么 link 有时不可点击,有时可点击(10% 的情况)吗?
当您将内容加载到 WKWebView 时,您可能会为您的网页设置错误的基础URL,这会导致无效 link,为了使其正常工作,您应该baseURL 为您的内容设置正确的 http 或 https URL,对于那些工作 link 只是因为他们的 href 中有完整的 url。
这里是 html 文本加载到 WKWebView 来说明效果:
webView.loadHTMLString(content, baseURL: NSURL(string: ""));
内容:
<html lang="en"><head><meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body>
<h1> click testing </h1>
<ul>
<li><a href="http://www.w3schools.com">Visit W3Schools</a></li>
<li><a href="/about">Un-Clickable without baseURL</a></li>
<li><a href="about://about">Clickable without baseURL</a></li>
</ul>
</body>
</html>
我假设你想要的是在某个地方有一些描述或文本,并允许在文本的某些部分内制作 clickable/tapped 而你想要使用 WKWebView
.
这个问题我也是用WKWebView
在很久以前做的某个app中解决的,当然有多种解决方法,这只是其中一种,没有别的。
正如某些人对您所说,您可以使用 loadHTMLString
函数以 JSON 或任何您想要的方式从您的服务器加载 HTML 字符串,但是非常重要的是HTML 格式正确无误。
关于您的评论 loadHTMLString
功能的一个非常重要的一点 ...您通常会希望在您按 link 时出现灰色背景见下图 ,如果 HTML 没有某种 CSS 样式,则不会发生,因为如果没有,它具有任何 [=15] 的默认样式=].
那么让我们看下面的代码:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var wkWebView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// The part of the HTMl you want to show
let description = "Let's start to visit the <a href=\"http://www.apple.com/\">Apple</a> website first and then if you want the <a href=\"http://www.w3schools.com\">Developer Apple</a> website."
// The default HTML with body and styles formatted and the description inside using string interpolation.
let htmlString = "<html><head><style type=\"text/css\">body {font-family: \"Lato-Regular\";font-size: 35px;color: #333333;margin: 0;}a {text-decoration: none; color: #999;}</style></head><body>\(description)</body></html>"
let preferences = WKPreferences()
preferences.javaScriptEnabled = false
// Configuration for any preferences you want to set
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
wkWebView = WKWebView(frame: CGRectMake(5, 35, self.view.bounds.width, self.view.bounds.height), configuration: configuration)
if let theWebView = wkWebView {
theWebView.loadHTMLString(htmlString, baseURL: NSURL())
theWebView.navigationDelegate = self
self.view.addSubview(theWebView)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Ok", style: .Default) { (UIAlertAction) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
})
presentViewController(alert, animated: true, completion: nil)
}
}
在上面的代码中,我将变量 description
设置为一些带有可点击元素的文本,并添加了两个委托方法 didStartProvisionalNavigation
和 didFinishNavigation
以显示 networkActivityIndicatorVisible
在状态栏中显示点击可点击文本时页面加载的一些进度。值得注意的是,在 htmlString
变量中我设置了一些样式来显示带有某些颜色和字体的 <a>
,这取决于您。
我也添加了 didFailProvisionalNavigation
功能以在某些情况下显示警报 url 无效,例如新添加的 HTTPTransportSecurityLayer
是 iOS 9只允许 https,在某些情况下你可以用它来验证 url 并知道错误的原因。
结果是正常的以下文本UIViewController
:
并且当您点击任何灰色文本时,url 将加载到同一个 WKWebView
中,当然您可以将其个性化为在在浏览器中使用或其他方式,由您决定。
然后点击 Apple:
可以立即看到结果
如果您点击 Developer Apple,您可以看到正在运行的警报,因为 http 协议在 HTTPTransportSecurityLayer
在 iOS 9:
如果您需要,我已准备好上传到 Github 的项目。希望对你有帮助。
解决方案是删除 contentInset
的使用。不幸的是,WKWebView
并不是为了处理它的使用而设计的(当 contentInset
为负数时),因此我们必须通过简单地向 [=26= 添加一个空的 div
来使用变通方法]字符串,就这样:
<div style='width:100%;height:100px'></div>
如果在不重新加载整个页面的情况下更改底部插图,可以先在底部插入一个巨大的 div
,然后通过添加正数 contentInset
来补偿它。这正是这个扩展的作用:
extension WKWebView {
/// The maximum possible height of the webView bottom content inset
@nonobjc static let maxBottomHeight: CGFloat = 20000
/// Provides an easy way to set the real bottom inset of the webView. Due to a bug in WKWebView framework, we first insert an emtpy div with the size WKWebView.maxContentSize on the bottom of the webView and compensate it by setting a positive contentInset (should be positive, otherwise the bug will be there again).
func set(bottomInset inset: CGFloat) {
self.scrollView.contentInset.bottom = inset - WKWebView.maxBottomHeight
}
}
不要忘记在 html 字符串的末尾添加 div
:
let htmlFooter = "<div style='width:100%;height:\(String(describing: WKWebView.maxBottomHeight))px'></div></body></html>"
在我用 Swift 2.1 编写的 iOS 应用程序中,我使用 WKWebView 加载 HTML 字符串,该字符串是使用 JSON 解析器从 wordpress 博客加载的.
我实现了委托方法 func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
并将 WKWebView 的导航委托设置为自身以处理 link 次按下。
现在,当我打开包含 WKWebView 的 ViewController 时,此委托方法被调用一次,这是您在加载 webView 时所期望的行为 - 因此委托似乎设置正确。
我现在的问题是,大多数时候 webView 包含的 link 是 不可点击的 。您通常会期望 灰色背景出现 ,当您按下 link 时,如下图所示。但大多数时候,当我按下 link 时,灰色背景不会出现,所以当我触摸时,委托方法不会被调用。这个问题肯定与 WKNavigationDelegate
的错误配置无关,因为有时 link 选择工作正常(大约 10 %)。
您知道为什么 link 有时不可点击,有时可点击(10% 的情况)吗?
当您将内容加载到 WKWebView 时,您可能会为您的网页设置错误的基础URL,这会导致无效 link,为了使其正常工作,您应该baseURL 为您的内容设置正确的 http 或 https URL,对于那些工作 link 只是因为他们的 href 中有完整的 url。
这里是 html 文本加载到 WKWebView 来说明效果:
webView.loadHTMLString(content, baseURL: NSURL(string: ""));
内容:
<html lang="en"><head><meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body>
<h1> click testing </h1>
<ul>
<li><a href="http://www.w3schools.com">Visit W3Schools</a></li>
<li><a href="/about">Un-Clickable without baseURL</a></li>
<li><a href="about://about">Clickable without baseURL</a></li>
</ul>
</body>
</html>
我假设你想要的是在某个地方有一些描述或文本,并允许在文本的某些部分内制作 clickable/tapped 而你想要使用 WKWebView
.
这个问题我也是用WKWebView
在很久以前做的某个app中解决的,当然有多种解决方法,这只是其中一种,没有别的。
正如某些人对您所说,您可以使用 loadHTMLString
函数以 JSON 或任何您想要的方式从您的服务器加载 HTML 字符串,但是非常重要的是HTML 格式正确无误。
关于您的评论 loadHTMLString
功能的一个非常重要的一点 ...您通常会希望在您按 link 时出现灰色背景见下图 ,如果 HTML 没有某种 CSS 样式,则不会发生,因为如果没有,它具有任何 [=15] 的默认样式=].
那么让我们看下面的代码:
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var wkWebView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// The part of the HTMl you want to show
let description = "Let's start to visit the <a href=\"http://www.apple.com/\">Apple</a> website first and then if you want the <a href=\"http://www.w3schools.com\">Developer Apple</a> website."
// The default HTML with body and styles formatted and the description inside using string interpolation.
let htmlString = "<html><head><style type=\"text/css\">body {font-family: \"Lato-Regular\";font-size: 35px;color: #333333;margin: 0;}a {text-decoration: none; color: #999;}</style></head><body>\(description)</body></html>"
let preferences = WKPreferences()
preferences.javaScriptEnabled = false
// Configuration for any preferences you want to set
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
wkWebView = WKWebView(frame: CGRectMake(5, 35, self.view.bounds.width, self.view.bounds.height), configuration: configuration)
if let theWebView = wkWebView {
theWebView.loadHTMLString(htmlString, baseURL: NSURL())
theWebView.navigationDelegate = self
self.view.addSubview(theWebView)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Ok", style: .Default) { (UIAlertAction) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
})
presentViewController(alert, animated: true, completion: nil)
}
}
在上面的代码中,我将变量 description
设置为一些带有可点击元素的文本,并添加了两个委托方法 didStartProvisionalNavigation
和 didFinishNavigation
以显示 networkActivityIndicatorVisible
在状态栏中显示点击可点击文本时页面加载的一些进度。值得注意的是,在 htmlString
变量中我设置了一些样式来显示带有某些颜色和字体的 <a>
,这取决于您。
我也添加了 didFailProvisionalNavigation
功能以在某些情况下显示警报 url 无效,例如新添加的 HTTPTransportSecurityLayer
是 iOS 9只允许 https,在某些情况下你可以用它来验证 url 并知道错误的原因。
结果是正常的以下文本UIViewController
:
并且当您点击任何灰色文本时,url 将加载到同一个 WKWebView
中,当然您可以将其个性化为在在浏览器中使用或其他方式,由您决定。
然后点击 Apple:
可以立即看到结果如果您点击 Developer Apple,您可以看到正在运行的警报,因为 http 协议在 HTTPTransportSecurityLayer
在 iOS 9:
如果您需要,我已准备好上传到 Github 的项目。希望对你有帮助。
解决方案是删除 contentInset
的使用。不幸的是,WKWebView
并不是为了处理它的使用而设计的(当 contentInset
为负数时),因此我们必须通过简单地向 [=26= 添加一个空的 div
来使用变通方法]字符串,就这样:
<div style='width:100%;height:100px'></div>
如果在不重新加载整个页面的情况下更改底部插图,可以先在底部插入一个巨大的 div
,然后通过添加正数 contentInset
来补偿它。这正是这个扩展的作用:
extension WKWebView {
/// The maximum possible height of the webView bottom content inset
@nonobjc static let maxBottomHeight: CGFloat = 20000
/// Provides an easy way to set the real bottom inset of the webView. Due to a bug in WKWebView framework, we first insert an emtpy div with the size WKWebView.maxContentSize on the bottom of the webView and compensate it by setting a positive contentInset (should be positive, otherwise the bug will be there again).
func set(bottomInset inset: CGFloat) {
self.scrollView.contentInset.bottom = inset - WKWebView.maxBottomHeight
}
}
不要忘记在 html 字符串的末尾添加 div
:
let htmlFooter = "<div style='width:100%;height:\(String(describing: WKWebView.maxBottomHeight))px'></div></body></html>"