Detect all UIWebViews load finish : Objective-C - ios

As mentioned in the title, I'm looking out for the way to detect all of the UIWebViews has finished load that are loading HTML string simultaneously.
I have one custom view in which there are 5 web views (1 for question and 4 for options). Each of them loading html string as :
[queWV loadHTMLString:queHtml baseURL:nil];
[opt1WV loadHTMLString:opt1Html baseURL:nil];
[opt2WV loadHTMLString:opt2Html baseURL:nil];
[opt3WV loadHTMLString:opt3Html baseURL:nil];
[opt4WV loadHTMLString:opt4Html baseURL:nil];
I've tried checking this with webViewDidFinishLoad
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if(webView == opt4WV)
{
//All web views has finished loading
}
}
But practically, its incorrect as the webViewDidFinishLoad method is getting called for random web views, depending on contents to load.
Is there any way to detect load finish for all the web views ?
Thanks !

Maybe I'm oversimplifying or not seeing something, but did you try to use webViewDidFinishLoad in a combination with the counter? So if you have 5 web views, implement a counter from 1 to 5 and count how many times does webViewDidFinishLoad get's called. When you get to 5 all views are loaded.

yes, use a counter to keep track and make sure all web views delegate are set to the same controller

May be helpful
take a NSInteger counter; globally
in viewDidLoad initialise counter = 0;
then
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
counter++;
if(counter == 5)
{
//All web views has finished loading
counter = 0; //again reset to 0
}
}
Happy coding...

in .h file create one counter like this
int webViewLoadCount = 0;
then trke this counter like this way
in .m file UIWebview delegate method
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *string = webView.request.URL.absoluteString;
if ([string rangeOfString:queHtml]) {
NSLog(#"queWV webview loaded with this %# ",queHtml);
webViewLoadCount = webViewLoadCount + 1;
} else if ([string rangeOfString:opt1Html]) {
NSLog(#"opt1WV webview loaded with this %# ",opt1Html);
webViewLoadCount = webViewLoadCount + 1;
} else if ([string rangeOfString:opt2Html]) {
NSLog(#"opt2WV webview loaded with this %# ",opt2Html);
webViewLoadCount = webViewLoadCount + 1;
}else if ([string rangeOfString:opt3Html]) {
NSLog(#"opt3WV webview loaded with this %# ",opt3Html);
webViewLoadCount = webViewLoadCount + 1;
}else if ([string rangeOfString:opt4Html]) {
NSLog(#"opt4WV webview loaded with this %# ",opt4Html);
webViewLoadCount = webViewLoadCount + 1;
}
}
i hope this will help you

declare the variable, "loaded" out of this function
int loaded = 0
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if(webView == queWV || webView == opt1WV || webView == opt2WV || webView == opt3WV || webView == opt4WV )
{
loaded += 1;
}
if (loaded ==5) {
// process
}
}

Related

To scroll UIScrollView programmatically but don't handle only this action in delegate methods?

In my class I wrote the following delegate methods:
scrollViewDidScroll:
scrollViewDidEndScrollingAnimation:
Then for this scrollView I use the following code:
scrollView.frame = ...;
scrollView.contentSize = ...;
[scrollView setContentOffset:... animated:NO];
The code and delegates work in a main thread but asynchronously to each other.
The problem is I don't want to call the described delegate methods with this code and. How to solve this issue? I can't simply write:
BOOL shouldCallDelegate = YES; //or NO
because I have other pieces of code which should be handled via these delegate methods.
UPDATED
I tried something like this:
NSLog(#"isMainThread == %d", [NSThread isMainThread]);
NSLog(#"isScrollViewBusy == %d", self.isScrollViewBusy);
self.isScrollViewBusy = YES;
scrollView.frame = ...;
scrollView.contentSize = ...;
[scrollView setContentOffset:... animated:NO];
self.isScrollViewBusy = NO;
Then in my delegate method:
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
NSLog(#"isMainThread2 == %d", [NSThread isMainThread]);
NSLog(#"isScrollViewBusy2 == %d", self.isScrollViewBusy);
...
}
You think that the app must write something like this?
isMainThread == 1
isScrollViewBusy == 0
isMainThread2 == 1
isScrollViewBusy2 == 0
In most cases it is so but when you try to rotate the screen:
isMainThread == 1
isScrollViewBusy == 0
isMainThread2 == 1
isScrollViewBusy2 == 1
So all the code is in the main thread but suddenly the first part of code is suspended?! somewhere between YES and NO while the app is processing the rotation and the delegate method is unexpectedly called
id<UIScrollViewDelegate> delegate = scrollView.delegate;
scrollView.delegate = nil;
// do your stuff
scrollView.delegate = delegate
The only improvement I found is if offset is less than 1 then I think that a scroll view is still not scrolled so I don't perform actions on this event.
It doesn't solve the problem completely but it appears much more rarely.

How can I prevent the webView from being visible till webViewDidFinishLoad is finished?

I'm removing content of the webView in the webViewDidFinishLoad. The problem is it first loads the page and shows all the content and then you will see the content I'm removing disappear. I would like it so that the user doesn't see anything disappear so the content should never been shown to the user.
This is my method :
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString* script = [NSString stringWithFormat:#"document.getElementById('menu').style.display='none';"];
[self.webView stringByEvaluatingJavaScriptFromString:script];
NSLog(#"gets");
}
The trick is use of isLoading property.
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if(!webView.isLoading){
//Has completely stopped..
}
}
Use webview.hidden = YES till the time you dont want to see the data and then set it as no again
You can use the UIWebView Delegate methods as shown below.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
webView.hidden = YES;
return YES;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
webView.hidden = NO;
}
Isn't the same thing work in viewDidLoad ?
-(void)viewDidLoad{
NSString* script = [NSString stringWithFormat:#"document.getElementById('menu').style.display='none';"];
[self.webView stringByEvaluatingJavaScriptFromString:script];
NSLog(#"gets");
}

Adding Loading Screens to multiple UIWebViews

Im building an app with multiple uiwebviews. I wanted to add loading screens to make the app easier to use. I've added one for one of my webviews using this code.
- (void)webViewDidStartLoad:(UIWebView *)vieWeb
{
_loadingmain.hidden=NO;
}
- (void)webViewDidFinishLoad:(UIWebView *)viewWeb
{
_loadingmain.hidden=YES;
}
viewWeb is the name of one of my uiwebviews. How would I add a load scree for my other two webviews? adding identical code with a different name for the webview causes the error "duplicate declaration of method webViewDidFinishLoad". Any help would be greatly appreciated. Thanks!
So you have multiple UIWebViews on one page, right? If so, you have a few options:
1) Create a subclass of UIWebView and set itself as the web view delegate, that way each UIWebView subclass handles it's own loading view.
2) You could also create multiple instances of your loading views and do something like
-(void)webViewDidStartLoad:(UIWebView *)webView
{
if( webView == self.webView1 )
{
[self.webView1 addSubview:self.loadingView1];
}
else if( webView == self.webView2 )
{
[self.webView2 addSubview:self.loadingView2];
}
//repeat for other webviews
}
-(void) webViewDidFinishLoad:(UIWebView *)webView
{
if( webView == self.webView1 )
{
[self.loadingView1 removeFromSuperview];
}
else if( webView == self.webView2 )
{
[self.loadingView2 removeFromSuperview];
}
//repeat for other webviews
}

Checking the UIWebView's URL

So I have an image that I would like to hide only if my UIWebView is currently on a certain URL. For example, if "example1.com/cheese" was currently being displayed in my UIWebView, then I will hide the image. I have no idea how to go about checking to see if a specific URL is loaded in though. I'm trying this:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request {
NSString *host = [request.URL host];
if ([host != isEqualToString:#"example1.com/cheese"]) {
image.hidden = NO;
}
else
image.hidden = YES;
}
My issue lies within my if statement. I'm unsure of how to do a "is not equal to this URL". Does anyone know what I need to change or add to fix this?
Update: This is the code I'm working with now, the error appearing is Use of undeclared identifier, host.:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request {
if (![host isEqualToString:#"exampleURL.com/cheese"]) {
image.hidden = NO;
} else {
image.hidden = YES;
}
}
This is basic Objective-C (really C) syntax:
if (![host isEqualToString:#"someURL"]) {
// doesn't match
} else {
// does match
}
The ! means "not". It negates the result of the expression. Since isEqualToString: returns YES if the two strings are equal, the ! negates it to NO. If the two strings are not equal, the NO result gets negated to YES.
You can also do this:
// Hide image if host matches "someURL"
image.hidden = [host isEqualToString:#"someURL"];

UIWebView's scrolling after textfield focus

I have UIView and UIWebView on screen. When I click on text field in website, web view content is going up. How could I force UIView to move as well then?
You can subscribe to either the UIKeyboardWillShowNotification or the UIKeyboardDidShowNotification, and move your UIView when you receive the notification. This process is described here:
Text, Web, and Editing Programming Guide for iOS: “Moving Content That Is Located Under the Keyboard”
Maybe this helps: I didn't want the UIWebView to scroll at all, including when focusing on a textfield.
You have to be the delegate of the UIWebView:
_webView.scrollView.delegate = self;
And then add this method
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
scrollView.contentOffset = CGPointZero;
}
UIWebView has a callback:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
This is triggered whenever a new URL request is about to load. From javascript, you could trigger a new request URL on the onfocus event of the tag, with a custom schema like:
window.location = "webViewCallback://somefunction";
Here's a script to put your custom event inside any html page to load.
You'll have to get the whole HTML before loading it to the UIWebView like this:
NSString *html = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"your URL"] encoding:NSUTF8StringEncoding error:nil];
Then insert the following inside the HTML text in a appropriate place:
<script>
var inputs = document.getElementsByTagName('input');
for(int i = 0; i < inputs.length; i++)
{
if(inputs[i].type = "text")
{
inputs[i].onfocus += "javascript:triggerCallback()";
}
}
function triggerCallback()
{
window.location = "webViewCallback://somefunction";
}
</script>
Then, on the callback you should do something like this:
-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
if ( [[inRequest URL] scheme] == #"webViewCallback" ) {
//Change the views position
return NO;
}
return YES;
}
That's it. Hope it helps.
Wow, I had the same problem few days ago, it was really annoying. I figured out that window.yPageOffset is changing, but as far as I know there aren't any events to bind when it changes. But maybe it will help you somehow. ;-)
I think you overwrote scrollViewDidScroll wrong.
You need to implement custom class for UIWevView and overwrite scrollViewDidScroll:
- (void) scrollViewDidScroll:(UIScrollView *)scrollView{
[super scrollViewDidScroll:scrollView];
[((id<UIScrollViewDelegate>)self.delegate) scrollViewDidScroll:scrollView];
}

Resources