我有一个从UIViewView到WKWebView的迁移问题,检测到使用WKWebView时滚动视图到达底部。在WKWebView之前,我使用UIScrollViewDelegate来检测用户是否通过滚动到WebView的末尾看到了所有内容。如果他这样做了,则启用了"确认"按钮。iPhone - 知道UIScrollView是到达顶部还是底部
现在有了WKWebView,这不再起作用了。我想原因是,当使用 WKWebView 并加载 html 字符串时,它会缩小视图以使内容完全可见。所以我不得不通过将视口附加到 html 字符串来设置视口。这将以与 UIWebView 相同的方式显示内容,提供 html 字符串,而无需设置视区。
但是现在加载时的UIScrollViewDelegate总是告诉底部已经到达。我猜,WKWebView 加载 html,以完全可见的方式缩放它,scrollViewDelegate 识别内容是完全可见的,之后视口进来并放大页面,因此需要垂直滚动来显示完整内容。但此时,我的"确认"按钮已经启用。
代码片段
override func scrollViewDidScroll(_ scrollView: UIScrollView){
let scrollViewHeight = scrollView.frame.size.height;
let scrollContentSizeHeight = scrollView.contentSize.height;
let scrollOffset = scrollView.contentOffset.y;
if (scrollOffset + scrollViewHeight == scrollContentSizeHeight)
{
self.confirmButton.isEnabled = true;
}
}
使用 WKWebView,scrollContentSizeHeight 始终与加载时的 scrollViewHeight 相同,但在 scrollViewDidScroll 委托函数调用多次(不滚动(后,scrollContentSizeHeight 大于实际大小的 scrollViewHeight。
但是现在加载时的UIScrollViewDelegate总是告诉底部 已经到达。
特定情况下的问题是UIScrollView
在完全加载WKWebView
之前调用委托。
使用一个私有实例变量来检查URL
是否完全加载。
var isURLLoaded = false
确认WKWebView
委托到您的视图控制器。
webView.scrollView.delegate = self
webView.navigationDelegate = self
并重写这些委托方法:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if isURLLoaded {
if scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height) {
confirmButton.isEnabled = true
} else if scrollView.contentOffset.y < scrollView.contentSize.height {
confirmButton.isEnabled = false
}
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
isURLLoaded = true
}
我为Wkwebview编写了用于读取javascript代码的scrollview扩展.通过它,您可以使用它来检查Webview是否到达页面末尾。使用前,请设置 Web 视图滚动委托。
extension BaseWebViewController: UIScrollViewDelegate {
func scrollViewDidEndDragging(_ scrollView: UIScrollView,
willDecelerate decelerate: Bool) {
webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
if complete != nil {
self.webView.evaluateJavaScript("document.body.scrollHeight", completionHandler: { (height, error) in
let bodyScrollHeight = height as! CGFloat
var bodyoffsetheight: CGFloat = 0
var htmloffsetheight: CGFloat = 0
var htmlclientheight: CGFloat = 0
var htmlscrollheight: CGFloat = 0
var wininnerheight: CGFloat = 0
var winpageoffset: CGFloat = 0
var winheight: CGFloat = 0
//body.offsetHeight
self.webView.evaluateJavaScript("document.body.offsetHeight", completionHandler: { (offsetHeight, error) in
bodyoffsetheight = offsetHeight as! CGFloat
self.webView.evaluateJavaScript("document.documentElement.offsetHeight", completionHandler: { (offsetHeight, error) in
htmloffsetheight = offsetHeight as! CGFloat
self.webView.evaluateJavaScript("document.documentElement.clientHeight", completionHandler: { (clientHeight, error) in
htmlclientheight = clientHeight as! CGFloat
self.webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (scrollHeight, error) in
htmlscrollheight = scrollHeight as! CGFloat
self.webView.evaluateJavaScript("window.innerHeight", completionHandler: { (winHeight, error) in
if error != nil {
wininnerheight = -1
} else {
wininnerheight = winHeight as! CGFloat
}
self.webView.evaluateJavaScript("window.pageYOffset", completionHandler: { (winpageOffset, error) in
winpageoffset = winpageOffset as! CGFloat
let docHeight = max(bodyScrollHeight, bodyoffsetheight, htmlclientheight, htmlscrollheight,htmloffsetheight)
winheight = wininnerheight >= 0 ? wininnerheight : htmloffsetheight
let winBottom = winheight + winpageoffset
if (winBottom >= docHeight) {
print("end scrolling")
}
})
})
})
})
})
})
})
}
})
}
}
滚动到达结束后,您将在控制台中看到"结束滚动">
在类内创建一个 ScrollView,WKWebView 内部嵌入了一个滚动视图,使你创建的滚动视图相对于嵌入的滚动视图并实现方法:
func scrollViewDidScroll(_ scrollView: UIScrollView){
if (scrollView.contentOffset.y + 1) >= (scrollView.contentSize.height - scrollView.frame.size.height) {
//bottom reached
your code here
}
}
然后,让你的类继承自 UIScrollViewDelegate
:类 : UIViewController,
func updateButtonState(_ scrollView : UIScrollView){
if isURLLoaded {
if scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height) {
confirmButton.isEnabled = true
} else if scrollView.contentOffset.y < scrollView.contentSize.height {
confirmButton.isEnabled = false
}
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.updateButtonState(scrollView);
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
isURLLoaded = true
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500), execute:{
self.updateButtonState(webView.scrollView)
});
}
不幸的是,我找不到 scrollView 准备好评估的回调,所以我将超时设置为 500 毫秒,通过此修改它按预期工作