Silver Challenge Solution


#1

The hardest part of the challenge was figuring out how to get the toolbar to be positioned at the bottom. The nav bar at the top was causing the view to be shifted downward by the height of the navbar. The I realized the navigation bar was created in AppDelegate so I simply added a navHeight property in the WebViewController that I could set in AppDelegate. I used a method in the WebViewController to create the barbutton items. I did this so I could determine if the back/forward buttons should be enabled and create them at the same time using one method. I hope this is acceptable. Here’s the code.

NerdfeedAppDelegate.m

#import "WebViewController.h"

@implementation NerdfeedAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    
    ListViewController *lvc = [[ListViewController alloc] init];
    UINavigationController *masterNav = [[UINavigationController alloc] initWithRootViewController:lvc];
    
    
    WebViewController *wvc = [[WebViewController alloc] init];
    [wvc setNavHeight:[masterNav toolbar].frame.size.height];
    
    [lvc setWebViewController:wvc];
    
    [[self window] setRootViewController:masterNav];
    
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

WebViewController.h

@interface WebViewController : UIViewController <UIWebViewDelegate>
{
    UIWebView *webView;
    UIToolbar *tb;
}

@property (nonatomic)CGFloat navHeight;
@property (nonatomic, readonly)UIWebView *webView;

@end

WebViewController.m

@implementation WebViewController


-(void)loadView
{
    CGRect screenFrame = [[UIScreen mainScreen] applicationFrame];
    webView = [[UIWebView alloc] initWithFrame:screenFrame];
    [webView setDelegate:self];

    //Setup frame for the toolbar
    CGFloat xPos   = 0;
    CGFloat yPos   = 0 + CGRectGetHeight(webView.bounds) - 2*[self navHeight];
    CGFloat width  = CGRectGetWidth(webView.bounds);
    CGFloat height = [self navHeight];
    
    tb = [[UIToolbar alloc] initWithFrame:CGRectMake(xPos, yPos, width, height)];
    
    [tb setBarStyle:UIBarStyleDefault];
    [webView addSubview:tb];
    [webView setScalesPageToFit:YES];
    
    //Setup barbutton items
    [self barButtonItems];
            
    [self setView:webView];
}

-(void)webViewDidFinishLoad:(UIWebView *)wv
{
    [self barButtonItems];
}

-(void)priorPage
{
    [[self webView] goBack];
}

-(void)forward
{
    [[self webView] goForward];
}

-(void)barButtonItems
{
    UIBarButtonItem *bbiGB = [[UIBarButtonItem alloc] initWithTitle:@"<-Backward"
                                             style:UIBarButtonItemStyleBordered
                                            target:self
                                            action:@selector(priorPage)];
    UIBarButtonItem *bbiGF = [[UIBarButtonItem alloc] initWithTitle:@"Forward->"
                                             style:UIBarButtonItemStyleBordered
                                            target:self
                                            action:@selector(forward)];
        
    NSArray *bbiArray = [[NSArray alloc] initWithObjects:bbiGB, bbiGF, nil];
    
    [tb setItems];
    
    //Set enabled or disabled buttons. The canGoBack canGoForward are built in properties of UIWebView
    if ([webView canGoBack])
    {
        [bbiGB setEnabled:YES];
    }
    else
    {
        [bbiGB setEnabled:NO];
    }
    
    if ([webView canGoForward])
    {
        [bbiGF setEnabled:YES];
    }
    else
    {
        [bbiGF setEnabled:NO];
    }

}

-(UIWebView *)webView
{
    return (UIWebView *)[self view];
}

@end

#2

Hi Jeff,

You don’t need to create the toolbar manually. Since WebViewController is inside a navigation controller (masterNav), all you have to do is ask it to display the toolbar for you, and it does all the math and geometry automatically:

In WebViewController.m

- (void)viewWillApper:
{
    [[self navigationController] setToolbarHidden:NO animated:YES];
    // Proceed to create the bar button items...
    …
}

And in viewWillDisappear:

[code]

  • (void)viewWillDisappear:(BOOL)animated
    {
    [[self navigationController] setToolbarHidden:YES animated:NO];
    }[/code]

If you want to see the whole file:

@implementation WebViewController
@synthesize webView;

- (void)viewWillAppear:(BOOL)animated
{
    [[self navigationController] setToolbarHidden:NO animated:NO];
    
    previous = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRewind target:[self webView] action:@selector(goBack)];
    next = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFastForward target:[self webView] action:@selector(goForward)];
    
    UIBarButtonItem *flex = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
    
    ai = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    
    UIBarButtonItem *loading = [[UIBarButtonItem alloc] initWithCustomView:ai];
    
    [previous setEnabled:NO];
    [next setEnabled:NO];
    [self setToolbarItems:[NSArray arrayWithObjects:flex, previous, flex, next, flex, loading, nil]];   
}


- (void)loadView
{
    CGRect screenFrame = [[UIScreen mainScreen] applicationFrame];
    
    UIWebView *wv = [[UIWebView alloc] initWithFrame:screenFrame];
    
    [wv setDelegate:self];
    
    [wv setScalesPageToFit:YES];
    
    [self setView:wv];
}


- (void)viewWillDisappear:(BOOL)animated
{
    [[self navigationController] setToolbarHidden:YES animated:NO];
}


- (UIWebView *)webView
{
    return (UIWebView *)[self view];
}


#pragma mark UIWebViewDelegate
- (void)webViewDidStartLoad:(UIWebView *)webView
{
    [ai startAnimating];
}


- (void)webViewDidFinishLoad:(UIWebView *)wv
{
    [previous setEnabled:NO];
    [next setEnabled:NO];
    [ai stopAnimating];

    if ([wv canGoForward]) {
        [next setEnabled:YES];
    }

    if ([wv canGoBack]) {
        [previous setEnabled:YES];
    }

}

@end

Cheers!

Gilmar


#3

Thanks, Gilmar. I’ll test that out.


#4

Hi,

I tried to implement the solution of Plastic but webViewDidFinishLoad never gets called.

Does anybody know why ?

Cheers
Michael


#5

When I try to load google in the UIWebView webViewDidFinishLoad gets called but not for preview audio files.

Anybody ?

Cheers
Michael