每次加载页面中的任何对象时,似乎都会发送 webViewDidFinishLoad 消息。有没有办法确定所有内容的加载都已完成?
10 回答
我猜 iframe 会导致webViewDidStartLoad
/webViewDidFinishLoad
对。
作为答案提到的[webView isLoading]
支票对我不起作用;false
即使在两次webViewDidFinishLoad
调用中的第一次之后它也返回了。相反,我跟踪加载如下:
- (void)webViewDidStartLoad:(UIWebView *)webView {
webViewLoads_++;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
webViewLoads_--;
if (webViewLoads_ > 0) {
return;
}
…
}
- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error {
webViewLoads_--;
}
(请注意,这仅在开始/完成对不连续出现的情况下才有效,但根据我的经验,到目前为止还没有发生。)
检查这个,它肯定对你有用:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if ([[webView stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {
// UIWebView object has fully loaded.
}
}
有趣的是,我没想到它会那样工作。虽然我确定还有其他方法可以做到这一点(有没有办法从 webViewDidFinishLoad 消息中提取 URL,以便您可以看到哪个是完成加载的主页?),但我能想到的主要是使用估计进度来检查页面的进度,并在 100% 完成加载时触发你想做的任何事情,这就是我在我的应用程序中所做的。谷歌“iphone webviewestimatedprogress”并单击第一个链接以获取我编写的有关如何执行此操作的指南。
更新:
请在下面使用 phopkins 的答案而不是我的答案!在您的应用程序中使用私有 API 是一个坏主意,您可能会被拒绝,而他的解决方案是正确的。
另一种以较少控制监视加载进度的方法是观察 WebViewProgressEstimateChangedNotification、WebViewProgressFinishedNotification 和 WebViewProgressStartedNotification 通知。例如,您可以观察这些通知以在您的应用程序中实现一个简单的进度指示器。您可以通过调用estimatedProgress 方法来更新进度指示器,以估计当前加载的内容量。
您还可以使用我编写的这个简短类别,它将块添加到 UIWebView 中,还允许您在默认 UIWebView 行为(在每个对象加载后收到通知)或“预期”行为(仅在页面完全加载时收到通知)之间进行选择。
我需要从尚未完全加载的页面中捕获一个变量。
这对我有用:
- (void) webViewDidFinishLoad:(UIWebView *)webView {
NSString *valueID = [webView stringByEvaluatingJavaScriptFromString:@"document.valueID;"];
if([valueID isEqualToString:@""]){
[webView reload];
return;
}
//page loaded
}
所有选项都不适用于我的用例。我使用 phopkins 的例子稍作修改。我发现如果加载到 webview 中的 HTML 包含一个图像,该图像将是一个单独的请求,并且是连续发生的,所以我们必须考虑到这一点,我用计时器做到了这一点。不是最好的解决方案,但它似乎有效。:
- (void)webViewActuallyFinished {
_webViewLoads--;
if (_webViewLoads > 0) {
return;
}
//Actually done loading
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
_webViewLoads++;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(webViewActuallyFinished) userInfo:nil repeats:NO];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
_webViewLoads--;
}
嗨,它可能已经有点远了,但我希望这会有所帮助。
我只是在它进入 webViewDidFinishLoad 方法时使用了一个通知,以便我可以捕获该方法的一个实例,然后我将检测到通知并从那里执行我的逻辑。
希望这可以帮助。它不会捕获 webViewDidFinishLoad 方法的最后一个调用实例,但允许您在调用它后执行某些操作,并且也不会重复调用该特定方法(例如显示一个按钮)。
** * ** * ***编辑* ** * ** * **
我做了一个测试并设法测试了它。它确实有效,并且在加载整个页面后将调用从通知中调用的方法。
或者,我认为您可以在委托方法 webViewDidStartLoad 和 webViewDidFinishLoad 上进行计数器,以确保在运行代码之前它们是相同的。不过,这是一个丑陋的 hack,因为我们永远不会知道它会被调用多少次,除非像我一样,您正在加载 html 提要并且可以添加 JavaScript 来检查您正在加载的页面上有多少元素。我只是分享一些我试图解决这个问题的方法。希望能帮助到你。
鼓励反馈。谢谢!
这是我在 DOM 加载时用来显示微调器的方法,它建立在 @Vinod 的回答之上。
注意 betweenwebViewDidStartLoad
和readyState是从上一个请求(如果有的话)完成webViewDidFinishLoad
的,这就是为什么轮询应该在.webViewDidFinishLoad
readyState可能的值是loading、interactive或completed(也许nil?)
- (void)webViewDidStartLoad:(UIWebView *)webView {
[self spinnerOn];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self startDOMCompletionPolling];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[self startDOMCompletionPolling];
}
- (void)startDOMCompletionPolling {
if (self.domCompletionListener) {
[self.domCompletionListener invalidate];
}
self.domCompletionListener = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(checkDOMCompletion) userInfo:nil repeats:YES];
}
- (void)checkDOMCompletion {
NSString *readyState = [self.webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
if (readyState != nil) {
if (readyState.length > 0) {
if ([readyState isEqualToString:@"loading"]) { //keep polling
return;
}
}
}
//'completed', 'interactive', nil, others -> hide spinner
[self.domCompletionListener invalidate];
[self spinnerOff];
}
我这样做的方式是这样的:
- (void)webViewDidFinishLoad:(UIWebView *)webview {
if (webview.loading)
return;
// now really done loading code goes next
[logic]
}