UIWebView: Show image while loading

dhrm picture dhrm · Dec 7, 2011 · Viewed 8.8k times · Source

In my storyboard I have a view with a UIWebView which is filling the entire area except from tab and navigation bar. The controller for the view is implements the protocol UIWebViewDelegate. The controller is set as delegate for the UIWebView:

#pragma mark - UIWebViewDelegate
- (void) webViewDidStartLoad:(UIWebView *)webView {
    NSLog(@"webViewDidStartLoad");
}

- (void) webViewDidFinishLoad:(UIWebView *)webView {
    NSLog(@"webViewDidFinishLoad");
}

While the UIWebView is loading I'll show an black background with an image stating that it is loading. How can I do that?

EDIT1: I'm trying to add the default ActivityIndicatorView instead of a static image. But this just gives me a black background with a small white area. What is the problem?

UIImageView *loadingImageView = [[UIImageView alloc] initWithFrame:webView.frame];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
UIImage *spacer = [UIImage imageNamed:@"spacer"];    
UIGraphicsBeginImageContext(spinner.frame.size);
[spacer drawInRect:CGRectMake(0,0,spinner.frame.size.width,spinner.frame.size.height)];
UIImage* resizedSpacer = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
loadingImageView.image = resizedSpacer;
[loadingImageView setBackgroundColor:[UIColor blackColor]];
[loadingImageView setContentMode:UIViewContentModeCenter];
self.loadingImageView = loadingImageView;

Answer

Mutix picture Mutix · Dec 7, 2011

In your controller .h

@property (nonatomic, retain) UIImageView *loadingImageView;

In your controller .m

@synthesize loadingImageView;

- (void)viewDidLoad {

    ...

    UIImageView *theLoadingImageView = [[UIImageView alloc] initWithFrame:webView.frame];
    theLoadingImageView.image = [UIImage imageNamed:@"your_image.png"];
    self.loadingImageView = theLoadingImageView;
    [theLoadingImageView release];

    ...
}

- (void) webViewDidStartLoad:(UIWebView *)webView {

    [self.view addSubview:self.loadingImageView];
}

- (void) webViewDidFinishLoad:(UIWebView *)webView {

    [self.loadingImageView removeFromSuperview];
}

EDIT 1:

If you would like to show an ActivityIndicatorView instead of a static image, here is a little helper class that I love to use:

LoadingIndicator.h

#import <UIKit/UIKit.h>


@interface LoadingIndicator : UIView {

    UIActivityIndicatorView *activityIndicator;
    UILabel *labelMessage;

}

@property(retain) UIActivityIndicatorView *activityIndicator;
@property(retain) UILabel *labelMessage;

- (id)init;
- (void)show:(NSString *)theMessage;
- (void)hide;
- (void)refreshPosition;

@end

LoadingIndicator.m

#import "LoadingIndicator.h"
#import <QuartzCore/QuartzCore.h>

@implementation LoadingIndicator

@synthesize labelMessage, activityIndicator;

- (id)init {    
    if (self = [super initWithFrame:CGRectMake(25, 130, 270, 100)]) {

        // Vue
        self.backgroundColor = [UIColor blackColor];
        self.alpha = 0.80;
        self.layer.cornerRadius = 5;

        // Label : message
        UILabel *theLabelMessage = [[UILabel alloc] initWithFrame:CGRectMake(15, 65, 240, 20)];
        theLabelMessage.backgroundColor = [UIColor clearColor];
        theLabelMessage.textColor = [UIColor whiteColor];
        theLabelMessage.text = NSLocalizedString(@"Loading", @"Loading");
        theLabelMessage.textAlignment = UITextAlignmentCenter;
        theLabelMessage.font = [UIFont boldSystemFontOfSize:16];
        theLabelMessage.adjustsFontSizeToFitWidth = YES;

        self.labelMessage = theLabelMessage;
        [self addSubview:theLabelMessage];
        [theLabelMessage release];

        // Activity Indicator
        UIActivityIndicatorView *theActivityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
        theActivityIndicator.frame = CGRectMake(115, 15, 40, 40);

        self.activityIndicator = theActivityIndicator;
        [self addSubview:theActivityIndicator];
        [theActivityIndicator release];

    }
    return self;
}

- (void)show:(NSString *)theMessage {

    self.labelMessage.text = theMessage;
    [self.activityIndicator startAnimating];
    self.hidden = NO;
    [self.superview bringSubviewToFront:self];
        [self refreshPosition];
}

- (void)hide {
    [self.activityIndicator stopAnimating];
    self.hidden = YES;
}

- (void)refreshPosition {

    self.center = self.superview.center;
}

- (void)dealloc {
    self.labelMessage = nil;
    self.activityIndicator = nil;

    [super dealloc];
}

@end

Then in your view.h

#import <UIKit/UIKit.h>
#import "LoadingIndicator.h"


@interface YourView : UIView {

    LoadingIndicator *loadingIndicator;

}

@property(retain) LoadingIndicator *loadingIndicator;

- (void)showLoadingIndicator:(NSString *)theMessage;
- (void)hideLoadingIndicator;

@end

In your view.m

#import "YourView.h"


@implementation YourView

@synthesize loadingIndicator;


- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {

        ...

        // Add your UIWebView etc

        ...

        // Loading Indicator
        LoadingIndicator *theLoadingIndicator = [[LoadingIndicator alloc] init];
        theLoadingIndicator.hidden = YES;   // Hidden by default

        self.loadingIndicator = theLoadingIndicator;
        [self addSubview:theLoadingIndicator];
        [theLoadingIndicator release];

        ...


    }
    return self;
}

- (void)showLoadingIndicator:(NSString *)theMessage {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [self.loadingIndicator performSelectorOnMainThread:@selector(show:) withObject:theMessage waitUntilDone:NO];

    [pool release];
}

- (void)hideLoadingIndicator {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [self.loadingIndicator performSelectorOnMainThread:@selector(hide) withObject:nil waitUntilDone:NO];

    [pool release];
}

- (void)dealloc {
    self.loadingIndicator = nil;

    [super dealloc];
}


@end

Finally in your WebView delegate:

- (void) webViewDidStartLoad:(UIWebView *)webView {

    [(YourView *)self.view showLoadingIndicator:@"Loading"];
}

- (void) webViewDidFinishLoad:(UIWebView *)webView {

    [(YourView *)self.view hideLoadingIndicator];
}

This will look something like this:

enter image description here