webViewDidFinishLoad did finish loading but didn't finish showing content on screen - ios

I'm using webViewDidFinishLoad a lot in my app and there's something about UIWebView that really bugs me, well, actually two things.
The first, when I load new content to a UIWebView I will see for half a second the last page that was loaded to the same UIWebView what will force me to "clean" the UIWebView using something like:
[_mainWebView stringByEvaluatingJavaScriptFromString:#"document.open();document.close();"];
before loading the new content.
The second issue I have and that's the main issue for this question is that if i'll load some new content to my UIWebView and do something like this:
[_mainWebView loadHTMLString:htmlString baseURL:nil];
...
- (void)webViewDidFinishLoad:(UIWebView *)webView {
_mainWebView.alpha = 1;
}
In some cases the UIWebView will show up white for half a second before showing up the content. I'm guessing that the content is already loaded into the UIWebView and that's why webViewDidFinishLoad:webView is firing but for small html pages showing to content takes loner than the actual load. Is there any workaround I can use to avoid the blank screen that is showing for a sec or so but still save that second?
I thought about animating the alpha from 0 to 1 but that solution feels kinda lame to me.

Try adding a javascript callback so you know when the web view contents have actually loaded: Javascript in UIWebView callback to C/Objective-C

Related

Webview scaleToFitPage doesn't scale page to fit in the webView

I am building a simple iOS application in Swift which is built with a webView inside the view. When load a Motion jpeg (mjpeg) in the webView and set
let reqObj = URLRequest(url: url! as URL)
vidView.delegate = self
vidView.scalesPageToFit = true
vidView.loadRequest(reqObj)
the pages load as I want in the right scale but after 1-2seconds the web view zooms in without any reason??? It seems to work but goes back and fourth between the scale I want and the zoomed in scale that i down want. I have read that one can set something to the html meta but don't understand how if this is the problem???
This is what I want it to be like
but this is what It goes to after a few seconds
This is what I don't want it to be like
The web view goes between these 2 content the whole time
Please if someone could help me with this matter and maybe knows what the problem is.

ios webview loadHTML string with link css

I load html string in which i link a local css file that lies in docment folder,
...<head><link href="a.css">...</head>...
Then i call webview.loadHTML:htmlstring baseURL:docURL;
the css was loaded OK. Then I change the a.css 's body {background:url(b.gif);} //previous is a.gif, then I pop the webview's view controller, and re-push a new one in which the webview load the same html string that link same css but the body's background image has been changed. Now comes the problem: Some times the webview load the changed background, while some times it will load old image though the css changed! And maybe I realloc the view controller some times, it maybe load the right one!
Can anyone teach me how to fix it?
Thanks a lot!

UIWebView serialization after content has been rendered

I have a very large HTML Document that I need to show in my app. It utilizes CSS Columns, and scrolls horizontally. What I try to do is archive the UIWebView that renders the document in its current state, so that I can unarchive it from CoreData and don't have to let the user wait for a few seconds until it's rendered. So inside my UIWebViewDelegate, I serialize using the following method when webViewDidFinishLoad is called (the content is loaded from string, not from external sources):
[NSKeyedArchiver archivedDataWithRootObject:self.webView];
I checked if webViewDidFinishLoad is called multiple times, but it isn't. This and the core data saving actually works, i.e. it does save and load properly the next time the app is launched. However, while it saves the UIWebView itself, it seems like the content isn't loaded into it, which makes the whole procedure kinda useless for my purpose. Is my understanding of saving an object this way wrong, or is it simply a question of implementation?
Many thanks!
I dont think you should be archiving the UIWebview. Instead you can save the html document fil with custom CSS elements in the documents directory of the app and render it using the filepath using the following code.
self.webview.scalesPageToFit= YES;
[self.webview loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath]]];

How can I detect the completion of view layout for a UIWebView

I want to allow a user to associate a zoom factor with a document and use it as a starting point when displaying that document inside a UIWebView. It seems, however, that webViewDidFinishLoad: only indicates the end of in-memory loading, not including rendering or layout. Here's sample code to demonstrate the problem:
- (void)viewDidLoad {
[super viewDidLoad];
UIWebView *webView = (UIWebView *)self.view;
webView.delegate = self;
webView.scalesPageToFit = YES;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSString *urlString = [[NSBundle mainBundle] pathForResource:#"Doc" ofType:#"pdf"];
NSURL *file = [NSURL fileURLWithPath:urlString];
[(UIWebView *)self.view loadRequest:[NSURLRequest requestWithURL:file]];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (!webView.isLoading) {
[webView.scrollView setZoomScale:1.5 animated:YES];
}
}
The call to setZoomScale: executes with no effect (i.e. the file is displayed with a zoom factor of 1.0), apparently because it happens before the scroll view is in some state where it can deal with it. If I change the final method above to what follows, everything works as I'd hoped.
- (void)delayedZoomMethod {
[((UIWebView *)self.view).scrollView setZoomScale:1.5 animated:YES];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self performSelector:#selector(delayedZoomMethod) withObject:nil afterDelay:1.0];
}
This, of course, is a bad idea because the 1.0 delay is arbitrary, probably too long for the vast majority of cases, and will likely be too short under some unknown set of conditions.
The docs say, "Your application can access the scroll view if it wants to customize the scrolling behavior of the web view." Does anyone know of a notification, or property in the web view or its scroll view, that I could observe to be told when that statement becomes true?
If you have control of the html code this may help. I've been able to have html events trigger objC methods in the following manner.
html event triggers javascript that writes a string to window.location
the uiwebview then uses uiwebviewdelegate to receive the string with this function
webView:shouldStartLoadWithRequest:navigationType:
It's kind of hacky.
But I don't think there is a way to know the web view has finished rendering, unless you wrote the html page and can put a js function in to execute at the end of the page.
If you are using UIWebView to preview PDF files, then it may not be the best way. There is a QLPreViewController (from iOS 4.0) that is intended for this purpose. A Quick Look preview controller can display previews for the following items:
iWork documents
Microsoft Office documents (Office ‘97 and newer)
Rich Text Format (RTF) documents
PDF files
Images
Text files whose uniform type identifier (UTI) conforms to the
public.text type (see Uniform Type Identifiers Reference)
Comma-separated value (csv) files
If I change the final method above to what follows, everything works
as I'd hoped.
This, of course, is a bad idea because the 1.0 delay is arbitrary,
probably too long for the vast majority of cases, and will likely be
too short under some unknown set of conditions.
The docs say, "Your application can access the scroll view if it wants
to customize the scrolling behavior of the web view."
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (!webView.isLoading) //WEBDIDFINISHLOAD? {
[webView.scrollView setZoomScale:1.5 animated:YES];
}
}
look, the didFinishLoadMethod is called by an asynchronous notification from NSURLConnection,
its not necessarily in the main thread (since your UI update is not working)
The performSelector..after delay method is fine. The delay doesnt even really mean anything,
You are just jumping to the main thread to do your UI update and allowing the
NSURLConnection notification to complete.
It probably wouldnt matter if you said afterDelay:0.0
This is a common situation in iOS and OSX, you have to figure out what threads are capable of updating the UI, GCD, NSOperationQueues, and background runLoops on created threads all complicate this.
You found your solution, but you need to know what it means. Do the call to performSelector on mainThread, set a short delay and its fixed.

How to calculate scrollWidth of HTML page for fixed height without using UIWebView

We can use the following to calculate the scrollWidth of an HTML page in a UIWebView with a fixed height.
[webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.scrollWidth"]
Is it possible to do this evaluation on local HTML pages without loading a request into a UIWebView?
Would like this to occur on a separate thread.
No(sort of). The html would need to be rendered in some capacity to be able to get any kind of measurements. The reason for this is inherent in the way html/css/javascript work together (javascript modifies html/css properties, css modifies html). If you had to get the width without using a UIWebView, you would be stuck with one of two options:
Render the page yourself, whether it's with your custom code (thousands of man hours, don't do this) or some open source library. I doubt this will be any faster than UIWebView, and will likely introduce unexpected bugs.
Measure the page in the background, and store that value somewhere. This would basically be a form of caching for the size. If the pages are static from when you ship, just do it manually, and hard code it. If they are dynamic, write a class to measure them on startup and store the value. The dynamic measurement would require UIWebView
EDIT:
Are you trying to do this because UIWebView is blocking you're main thread, causing jerkiness in your app? If so, have you considered trying something like this?:
UIWebView *webview = [[UIWebView alloc] initWithFrame:CGRectMake(0,0,320,460)];
webview.delegate = self;
[webview loadRequest: [NSURLRequest requestWithURL:[NSURL urlFromString:#"/path/to/file.html"]]];
... and then later on...
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
// run your code to get scroll width of page
}

Resources