iOS WKWebView检测何时到达底部

时间:2018-10-18 10:13:54

标签: ios swift uiwebview wkwebview

我有一个从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的实际大小。

4 个答案:

答案 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,