PDA

View Full Version : webView activityIndicator and Stop/Refresh help needed




troop231
Aug 16, 2011, 08:17 AM
Hello, I seem to be stuck on two problems, the first one being that my activityIndicator is not working at all, and the second problem is that I'm trying to combine the stop and refresh buttons into one button for a cleaner design. Any help is truly appreciated! Here is a screenshot and my code:

http://img845.imageshack.us/img845/4456/unledvte.png

Test.h:

#import <UIKit/UIKit.h>
@interface Test : UIViewController <UIWebViewDelegate> {
UIWebView *webView;
UIBarButtonItem *refreshButton;
UIBarButtonItem *backButton;
UIBarButtonItem *forwardButton;
UIBarButtonItem *stopButton;
UIActivityIndicatorView *activityIndicator;

}


@property (nonatomic, retain) IBOutlet UIWebView *webView;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *refreshButton;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *backButton;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *forwardButton;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *stopButton;
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activityIndicator;


-(IBAction)refreshWebView;
-(IBAction)goBack;
-(IBAction)goForward;
-(IBAction)stop;
-(void)actualizeButtons;

@end

and Test.m:

#import "Test.h"

@implementation Test

@synthesize webView;
@synthesize activityIndicator;
@synthesize refreshButton;
@synthesize backButton;
@synthesize forwardButton;
@synthesize stopButton;


- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation !=
UIInterfaceOrientationPortraitUpsideDown);
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Test";

NSString *urlAddress = @"http://www.macrumors.com";
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];


}

-(void)actualizeButtons {
backButton.enabled = [webView canGoBack];
forwardButton.enabled = [webView canGoForward];
}

-(IBAction)refreshWebView {
[webView reload];
}

-(IBAction)stop {
[webView stopLoading];

}

-(IBAction)goBack {
[webView goBack];
[self actualizeButtons];
}

-(IBAction)goForward{
[webView goForward];
[self actualizeButtons];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[activityIndicator stopAnimating];
stopButton.enabled = NO;
refreshButton.enabled = YES;

[self actualizeButtons];

}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
[activityIndicator stopAnimating];
stopButton.enabled = NO;
refreshButton.enabled = YES;

[self actualizeButtons];
}

- (void)webViewDidStartLoad:(UIWebView *)webView {
[activityIndicator startAnimating];
stopButton.enabled = YES;
refreshButton.enabled = NO;

[self actualizeButtons];

}




- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}


- (void)dealloc {
[super dealloc];
[refreshButton release];
[backButton release];
[forwardButton release];
[stopButton release];
[activityIndicator release];
[webView release];

}

@end



nickculbertson
Aug 16, 2011, 08:28 AM
To create a changing bar button you either have to destroy the button and create a new one or stack two toolbars. I prefer the second. Create two toolbars (one with the stop and one with refresh) and in your methods have something like.


-(IBAction)refreshWebView {
[webView reload];
toolbar1.hidden=NO; //stop toolbar
toolbar2.hidden=YES; //refresh toolbar
}

-(IBAction)stop {
[webView stopLoading];
toolbar1.hidden=YES; //stop toolbar
toolbar2.hidden=NO; //refresh toolbar

}




I can't help with the UIActivityIndicatorView.

Nick

ArtOfWarfare
Aug 16, 2011, 08:42 AM
Did you set up the activityIndicator in your XIB? Because I might have overlooked it, but I don't recall seeing you actually create it in your code.

troop231
Aug 16, 2011, 09:16 AM
To create a changing bar button you either have to destroy the button and create a new one or stack two toolbars. I prefer the second. Create two toolbars (one with the stop and one with refresh) and in your methods have something like.


-(IBAction)refreshWebView {
[webView reload];
toolbar1.hidden=NO; //stop toolbar
toolbar2.hidden=YES; //refresh toolbar
}

-(IBAction)stop {
[webView stopLoading];
toolbar1.hidden=YES; //stop toolbar
toolbar2.hidden=NO; //refresh toolbar

}




I can't help with the UIActivityIndicatorView.

Nick

Thanks, I might try your method here in a bit, but do you know how to destroy buttons? When the webpage is loading my current implementation is sporadic, meaning the stop and refresh buttons activate/deactivate 10 times probably before it finishes loading the page.

Did you set up the activityIndicator in your XIB? Because I might have overlooked it, but I don't recall seeing you actually create it in your code.

Yes, I have it in the code I posted above, and in Interface Builder I have the outlet setup for it.

troop231
Aug 16, 2011, 10:04 AM
Here is what I came up with, I made another toolbar and it seems to be working great, however the issue now is that when loading a webpage, the transition from a refresh to stop button is very sporadic and so are the back and forward buttons, I uploaded a YouTube video of the problem: http://www.youtube.com/watch?v=EfOHOXColyI

How could I fix this? Also I'm lost on the activityIndicator issue. Thanks again!

Revised code:

Test.h:

#import <UIKit/UIKit.h>
@interface Test : UIViewController <UIWebViewDelegate> {
UIWebView *webView;
UIBarButtonItem *refreshButton;
UIBarButtonItem *backButton;
UIBarButtonItem *forwardButton;
UIBarButtonItem *stopButton;
UIActivityIndicatorView *activityIndicator;
UIToolbar *toolbarStop;
UIToolbar *toolbarRefresh;
}


@property (nonatomic, retain) IBOutlet UIWebView *webView;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *refreshButton;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *backButton;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *forwardButton;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *stopButton;
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activityIndicator;
@property (nonatomic, retain) IBOutlet UIToolbar *toolbarStop;
@property (nonatomic, retain) IBOutlet UIToolbar *toolbarRefresh;

-(IBAction)refreshWebView;
-(IBAction)goBack;
-(IBAction)goForward;
-(IBAction)stop;
-(void)actualizeButtons;

@end

and Test.m:

#import "Test.h"

@implementation Test

@synthesize webView;
@synthesize activityIndicator;
@synthesize refreshButton;
@synthesize backButton;
@synthesize forwardButton;
@synthesize stopButton;
@synthesize toolbarStop;
@synthesize toolbarRefresh;


- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation !=
UIInterfaceOrientationPortraitUpsideDown);
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Test";

NSString *urlAddress = @"http://www.macrumors.com";
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];


}

-(void)actualizeButtons {
backButton.enabled = [webView canGoBack];
forwardButton.enabled = [webView canGoForward];
}

-(IBAction)refreshWebView {
toolbarStop.hidden = NO;
toolbarRefresh.hidden = YES;
[webView reload];


}

-(IBAction)stop {
toolbarStop.hidden = YES;
toolbarRefresh.hidden = NO;
[webView stopLoading];


}

-(IBAction)goBack {
[webView goBack];
[self actualizeButtons];
}

-(IBAction)goForward{
[webView goForward];
[self actualizeButtons];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[activityIndicator stopAnimating];
toolbarStop.hidden = YES;
toolbarRefresh.hidden = NO;

[self actualizeButtons];

}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
[activityIndicator stopAnimating];
toolbarStop.hidden = YES;
toolbarRefresh.hidden = NO;

[self actualizeButtons];
}

- (void)webViewDidStartLoad:(UIWebView *)webView {
[activityIndicator startAnimating];
toolbarStop.hidden = NO;
toolbarRefresh.hidden = YES;

[self actualizeButtons];

}




- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}


- (void)dealloc {
[super dealloc];
[refreshButton release];
[backButton release];
[forwardButton release];
[stopButton release];
[activityIndicator release];
[toolbarStop release];
[toolbarRefresh release];
[webView release];

}

@end

nickculbertson
Aug 16, 2011, 01:13 PM
The error has to be in the linking. Perhaps if you copy and pasted the toolbar you also copied it's method links? Another thing you could do is create a separate method that hides and shows each toolbar just to keep your refresh/stop methods clean. Also uiwebviews have built in refresh, back, forward, and stop methods if you right click the web view in ib. This can keep your code shorter.

Nick

North Bronson
Aug 16, 2011, 01:40 PM
I see that webViewDidFinishLoad: will probably be called multiple times while your page is loading. It's hard to definitively state "my page is finished" from that method alone. You could keep an instance variable and increment every time that webViewDidStartLoad: is called and then decrement every time webViewDidFinishLoad: or webView:didFailLoadWithError: is called; when you reach zero, you could choose to do your updating there.

A cleaner approach might be to use key-value observing. The UIWebView has properties that tell you whether or not it is currently loading or can go back or forward. If you can observe those properties and change your buttons when those properties change, that would probably be a much cleaner approach.

troop231
Aug 16, 2011, 02:37 PM
I solved the activityIndicator issue. I had to add this code: [webView addSubview: activityIndicator]; below my self.title = @"Test"; statement

Still kindof lost on the sporadic showing/hiding of the seperate toolbars. I read what you posted above but not sure how to implement it into my code.

North Bronson
Aug 16, 2011, 02:51 PM
I can't say I'm a big fan of swapping out two different toolbars. Use one toolbar and just set different arrays of toolbar items depending on what state your application is in. This feels like a cleaner approach.

You don't even need to manage your own toolbar. The navigation controller comes with its toolbar that you can use. The advantage is that the navigation controller will handle shrinking the height of the toolbar if the user rotates to landscape. With your own toolbar, you would need to handle these changes yourself.

troop231
Aug 16, 2011, 03:07 PM
I can't say I'm a big fan of swapping out two different toolbars. Use one toolbar and just set different arrays of toolbar items depending on what state your application is in. This feels like a cleaner approach.

You don't even need to manage your own toolbar. The navigation controller comes with its toolbar that you can use. The advantage is that the navigation controller will handle shrinking the height of the toolbar if the user rotates to landscape. With your own toolbar, you would need to handle these changes yourself.

I agree about clean code also. The problem is that I'm not using a navigation toolbar, but rather a general uitoolbar at the bottom. I figured out how to get rid of the sporadic back and forward button problem, I forgot to add two new buttons in my code. On one toolbar the button is named "backButton" and on the other toolbar it is "backButtonT" That solved that issue, I just need to figure out the refresh/stop problem now. Could you provide any examples of the way you described? Thanks!