我猜测iframes会引起webViewDidStartLoad
/webViewDidFinishLoad
这一对方法的调用。
一个回答中提到的[webView isLoading]
检查对我不起作用;即使在两次webViewDidFinishLoad
中的第一个调用后,它也返回了false
。相反,我通过以下方式跟踪加载:
- (void)webViewDidStartLoad:(UIWebView *)webView {
webViewLoads_++;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
webViewLoads_--;
if (webViewLoads_ > 0) {
return;
}
…
}
- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error {
webViewLoads_--;
}
(请注意,这仅在开始/完成对不是连续出现时起作用,但根据我的经验,到目前为止尚未发生。)
(void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error { -- webViewLoads_; }
- user692463检查这个,它一定适合你使用:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if ([[webView stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {
// UIWebView object has fully 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--;
}
- (void) webViewDidFinishLoad:(UIWebView *)webView {
NSString *valueID = [webView stringByEvaluatingJavaScriptFromString:@"document.valueID;"];
if([valueID isEqualToString:@""]){
[webView reload];
return;
}
//page loaded
}
另一种在较少控制下监视负载进度的方法是观察WebViewProgressEstimateChangedNotification、WebViewProgressFinishedNotification和WebViewProgressStartedNotification通知。例如,您可以观察这些通知以在应用程序中实现简单的进度指示器。您可以通过调用estimatedProgress方法来更新进度指示器,以获取当前已加载内容的估计量。
您还可以使用我编写的这个简短的类别,将块添加到UIWebView中,并让您选择默认UIWebView行为(在每个对象加载后得到通知),或“预期”的行为(仅在页面完全加载后得到通知)。
这是我用来在DOM加载时显示旋转器的代码,基于@Vinod的答案构建。
请注意,在webViewDidStartLoad
和webViewDidFinishLoad
之间,readyState从上一个请求(如果有)中变为completed,因此轮询应该在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];
}
嗨,可能有点远古了,但我希望这可以帮到你。
我刚刚在进入webViewDidFinishLoad方法时使用了一个通知,以便我可以捕获该方法的一个实例,然后我将检测通知并从那里执行我的逻辑。
希望这可以帮助你。它不会捕获webViewDidFinishLoad方法的最后一个调用实例,但允许您在调用特定方法后执行某些操作(例如显示按钮)而不重复调用该特定方法。
*********编辑*********
我进行了测试并成功测试了它。它实际上是有效的,并且从通知中调用的方法将在完整页面加载后调用。
另外,我认为您可以在委托方法webViewDidStartLoad和webViewDidFinishLoad上进行计数,以确保在运行代码之前它们是相同的。不过,这是一种丑陋的hack,因为我们永远不知道它会被调用多少次,除非像我一样,您正在加载一个HTML源并可以添加JavaScript来检查您正在加载的页面上有多少元素。我只是分享了一些我尝试解决此问题的方法。希望能有所帮助。
鼓励反馈。谢谢!
webViewDidFinishLoad
和在webViewDidFinishLoad
中创建通知来调用另一个方法之间有何区别? - Aaron Brager我的做法是这样的:
- (void)webViewDidFinishLoad:(UIWebView *)webview {
if (webview.loading)
return;
// now really done loading code goes next
[logic]
}