我有一个从UIViewView到WKWebView的迁移问题,使用WKWebView时检测到滚动视图到达底部。在WKWebView之前,我使用UIScrollViewDelegate通过滚动到WebView的末尾来检测用户是否看到了所有内容。如果他这样做,则启用“确认”按钮。 iPhone - knowing if a UIScrollView reached the top or bottom
现在使用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的实际大小。
答案 0 :(得分:4)
我为Wkwebview编写了scrollview扩展名,用于阅读JavaScript代码。通过该代码,您可以检查webview到达页面末尾的范围。在使用之前,请设置webview滚动委托。
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")
}
})
})
})
})
})
})
})
}
})
}
}
滚动到达终点后,您将在控制台“结束滚动”中看到
答案 1 :(得分:2)
但是现在,UIScrollViewDelegate在加载时总是告诉底部 已经达到。
在特定情况下,问题是UIScrollView
的委托在完全加载WKWebView
之前被调用。
采用一个私有实例变量来检查URL
是否已完全加载。
var isURLLoaded = false
确认WKWebView
委托给您的viewController。
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
}
答案 2 :(得分:0)
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的回调,因此我设置了500ms的超时时间,通过这种修改,它可以按预期工作
答案 3 :(得分:0)
在类内部创建一个ScrollView,WKWebView内嵌一个滚动视图,使创建的滚动视图与嵌入式滚动视图相对并实现方法:
Stepper
然后使您的类继承自UIScrollViewDelegate:
class:UIViewController,