Reputation: 101
For UIWebView, we can get content height by this:
[webView stringByEvaluatingJavaScriptFromString:@"document.body.offsetHeight"]
But WKWebView doesn't have this method and webView.scrollView.contentSize.height is not right.
(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
}
Thank you for your help!
Upvotes: 10
Views: 18595
Reputation: 2150
EDIT:
To get the best possible height calculation, in the end I did a few things to get the best height:
The above got the most accurate results for me.
ORIGINAL:
I've tried the scroll view KVO and I've tried evaluating javascript on the document, using clientHeight
, offsetHeight
, etc...
What worked for me eventually is: document.body.scrollHeight
. Or use the scrollHeight
of your top most element, e.g. a container div
.
I listen to the loading
WKWebview property changes using KVO:
[webview addObserver: self forKeyPath: NSStringFromSelector(@selector(loading)) options: NSKeyValueObservingOptionNew context: nil];
And then:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if(object == self.webview && [keyPath isEqualToString: NSStringFromSelector(@selector(loading))]) {
NSNumber *newValue = change[NSKeyValueChangeNewKey];
if(![newValue boolValue]) {
[self updateWebviewFrame];
}
}
}
The updateWebviewFrame
implementation:
[self.webview evaluateJavaScript: @"document.body.scrollHeight" completionHandler: ^(id response, NSError *error) {
CGRect frame = self.webview.frame;
frame.size.height = [response floatValue];
self.webview.frame = frame;
}];
Upvotes: 3
Reputation: 1
WKWebView didn't finish loading, when didFinishNavigation is called - Bug in WKWebView? WKWebView doesn't use delegation to let you know when content loading is complete. You can create a new thread to check the status of WKWebView.
override func viewDidLoad() {
super.viewDidLoad()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), {
while(self.webView?.loading == true){
sleep(1)
}
dispatch_async(dispatch_get_main_queue(), {
print(self.webView!.scrollView.contentSize.height)
})
})
}
Upvotes: 0
Reputation: 1974
I solved this problem with KVO.
First, addObserver for WKWebView's scrollView's contentSize like this:
addObserver(self, forKeyPath: "webView.scrollView.contentSize", options: .New, context: nil)
And next, receive the change like this:
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
if keyPath == "webView.scrollView.contentSize" {
if let nsSize = change[NSKeyValueChangeNewKey] as? NSValue {
let height = nsSize.CGSizeValue().height
// Do something here using content height.
}
}
}
It's easy to get webview's content height.
Don't forget to remove observer:
removeObserver(self, forKeyPath: "webView.scrollView.contentSize", context: nil)
I worte this line in deinit
.
Upvotes: 11
Reputation: 13266
You can get it like this:
self.webview.navigationDelegate = self;
- (void)webView:(WKWebView *)webview didFinishNavigation:(WKNavigation *)navigation{
// webview.scrollView.contentSize will equal {0,0} at this point so wait
[self checkIfWKWebViewReallyDidFinishLoading];
}
- (void)checkIfWKWebViewReallyDidFinishLoading{
_contentSize = _webview.scrollView.contentSize;
if (_contentSize.height == 0){
[self performSelector:@selector(WKWebViewDidFinishLoading) withObject:nil afterDelay:0.01];
}
}
Upvotes: 2