Tutorial: Building a Web Browser with UIWebView (Part 2)

Web Browser Address and Title Ba

Figure 1: Web Browser Address and Title Bar

A new version of this tutorial, updated for Xcode 5 and iOS 7, is available here: Building a Web Browser with UIWebView Revisited (Part 2)

In yesterdays tutorial, Building a Web Browser with UIWebView (Part 1) you completed a skeletal implementation of a web browser. In today’s tutorial you will build upon that code to add a Safari-like address bar as shown in Figure 1.

If you completed the previous tutorial you can simply continue on with your existing code, or if you prefer you can download the starting point code there: WebBrowser1.zip.

To implement the address bar you are going to programmatically create a UINavigationBar and add a UITextField to allow the user to type in a URL and a UILabel to display the page title.

Defining Properties for the New UI Elements

Open WebBrowserViewController.h and add the highlighted code. (I have omitted some of the exisiting code in the file for brevity).

@interface WebBrowserViewController : UIViewController<UIWebViewDelegate> {

//...

    UIBarButtonItem* mStop;
    UILabel* mPageTitle;
    UITextField* mAddressField;
}

//...

@property (nonatomic, retain) IBOutlet UIBarButtonItem* stop;

@property (nonatomic, retain) UILabel* pageTitle;
@property (nonatomic, retain) UITextField* addressField;

//...

@end

Lines 6, 7, 14 and 15 define the instance variables and properties you will use to refer to the title label and address field. Notice that the properties are not marked IBOutlet this is because you will not be using them in Interface Builder.

Next add the synthesize code to WebBrowserViewController.m at the top of the @implementation section.

@implementation WebBrowserViewController
//...
@synthesize pageTitle = mPageTitle;
@synthesize addressField = mAddressField;

Since the properties are marked retain, before you go any further, you may as well get the dealloc and viewDidUnload out of the way.

- (void)dealloc
{
    //...

    [mPageTitle release];
    [mAddressField release];
    [super dealloc];
}
- (void)viewDidUnload
{
    //...

    self.pageTitle = nil;
    self.addressField = nil;
    [super viewDidUnload];
}

Creating the New Elements

When you are creating UI elements programmatically it can take quite a bit of fiddling with the coordinates and spacing to get the layout to look good. Luckily in this case I have down the fiddling for you. Copy and paste the following into WebBrowserViewController.h.

#import "WebBrowserViewController.h"

static const CGFloat kNavBarHeight = 52.0f;
static const CGFloat kLabelHeight = 14.0f;
static const CGFloat kMargin = 10.0f;
static const CGFloat kSpacer = 2.0f;
static const CGFloat kLabelFontSize = 12.0f;
static const CGFloat kAddressHeight = 26.0f;

I’ll rarely say copy and paste the code (even though I am sure many people do it), but there is not much to be learnt from the above code. It is simply defines some constants that result in a nice layout.

Now locate viewDidLoad begin with this modification. (Note: the next 5 code boxes are code you add one after the other to viewDidLoad)

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    CGRect navBarFrame = self.view.bounds;
    navBarFrame.size.height = kNavBarHeight;
    UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:navBarFrame];
    navBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;

This code creates a UINavigationBar with the same width as the screen and with the height you defined at the top of the file. The autoresizing mask UIViewAutoresizingFlexibleWidth ensures that if the user rotates the device the navigation bar will expand or contract to fill the width of the screen.

Next you are going to add the title label to this navigation bar:

    CGRect labelFrame = CGRectMake(kMargin, kSpacer, 
                navBar.bounds.size.width - 2*kMargin, kLabelHeight);
    UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
    label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    label.backgroundColor = [UIColor clearColor];
    label.font = [UIFont systemFontOfSize:12];
    label.textAlignment = UITextAlignmentCenter;
    [navBar addSubview:label];
    self.pageTitle = label;
    [label release];

Lines 1-3 create the new UILabel. Lines 4-7 set various visual attributes. Line 8 adds the newly created label to the navigation bar. Line 9 initializes the property you created earlier on. From now on you can refer to the label as self.pageTitle. Since you are finished using label you release it on line 10.

    CGRect addressFrame = CGRectMake(kMargin, kSpacer*2.0 + kLabelHeight, 
                                     labelFrame.size.width, kAddressHeight);
    UITextField *address = [[UITextField alloc] initWithFrame:addressFrame];
    address.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    address.borderStyle = UITextBorderStyleRoundedRect;
    address.font = [UIFont systemFontOfSize:17];
    [navBar addSubview:address];
    self.addressField = address;
    [address release];

The code for creating the text field follows the same pattern as the label.

Next you need to add the navigation bar to the view controllers view (this is the view that contains all the elements you created in Interface Builder in the previous tutorial).

                
    [self.view addSubview:navBar];
    [navBar release];

Notice that once the variable navBar is released you no longer have a way of referring to the navigation bar. This is not a problem since you will not need to. It is worth mentioning that the reason the navigation bar does not disappear is because adding it as a subView causes it to be retained by the parent view.

Finally you need to adjust the frame of the web view to ensure that it is not partially covered by the navigation bar.

    CGRect webViewFrame = self.webView.frame;
    webViewFrame.origin.y = navBarFrame.origin.y + navBarFrame.size.height;
    webViewFrame.size.height = self.toolbar.frame.origin.y - webViewFrame.origin.y;
    self.webView.frame = webViewFrame;

Now you should be able to compile and run your project. At this point touching the address field will cause the on screen keyboard to appear, but clicking return will not cause the web view to load the entered address. The title bar also remains blank.

Making the Address Bar Work

To make the web view load the entered address you need to tell the address field what action it should take when the user finishes editing an address. You do this by setting an action for the UIControlEventEditingDidEndOnExit control event. Add the highlighted code into viewDidLoad.

    address.font = [UIFont systemFontOfSize:17];
    [address addTarget:self 
                action:@selector(loadAddress:event:) 
      forControlEvents:UIControlEventEditingDidEndOnExit];
    [navBar addSubview:address];

The @selector(...) syntax allows you to refer a method by name. So this line of code tells the address field to invoke the method loadAddress:event: on self which, in this case, is you view controller. You now need to implement this method.

You begin by adding the method declaration to WebBrowserViewController.h

- (void)loadAddress:(id)sender event:(UIEvent*)event;

and then the implementation in WebBrowserViewController.m

- (void)loadAddress:(id)sender event:(UIEvent *)event
{
    NSString* urlString = self.addressField.text;
    NSURL* url = [NSURL URLWithString:urlString];
    NSURLRequest* request = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:request];
}

The UIWebView class defines a method loadRequest: that takes an NSURLRequest object and starts the web view loading the new request. Line 3 retrieves the string from the address field. Line 4 uses the string to create a URL. Line 5 uses the URL to create an NSURLRequest. Finally, line 6 instructs the web view to load this new request.

Compile and run your project and confirm that you can successfully load another website. There are still some glitches with the address field. If you use the forward and back buttons the address field is out of sync with the displayed page. Tomorrow’s tutorial will address that problem.

Making the Title Bar Work

When a web page finishes loading you should update the title bar to reflect the title of the newly loaded page. Recall that UIWebView calls webViewDidFinishLoad: when a page finishes loading (or an error method). Add the following line of code to your webViewDidFinishLoad: implementation.

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    [self updateButtons];
    [self updateTitle:webView];
}

You have not defined updateTitle: yet so add the following declaration to WebBrowserViewController.h:

- (void)updateTitle:(UIWebView*)aWebView;

And now for the implementation… If you look at Apple’s documentation of UIWebView you’ll notice something odd; there is no method to get the title of the HTML document loaded in the web view. So how can we find out this information?

While there is not direct function to get the title of the page, there is a function that allows you to execute JavaScript. The JavaScript expression document.title can be used to get the page title. This leads to the following implementation:

- (void)updateTitle:(UIWebView*)aWebView
{
    NSString* pageTitle = [aWebView stringByEvaluatingJavaScriptFromString:@"document.title"];
    self.pageTitle.text = pageTitle; 
}

If you now compile and run your project the title of the page should appear when a page loads.

Remaining Issues

There are still a number of small issues that need to be taken care of. Tomorrow’s tutorial will address them. They are:

  • the address field can get out of sync with the displayed page,
  • the keyboard displayed is not the URL keyboard so it is awkward to type a URL,
  • the keyboard auto-capitalization mode is inappropriately set,
  • there is no clear button in the address field,
  • if the user omits the http:// the page will not load,
  • if an error occurs, the user is never informed.

Source Code Download

You can download the completed source code for this part of the project here WebBrowser2.zip

This web site is ad supported. If you would like to see other great tutorials like this one please visit one of our sponsors.


About idz

A professional software engineer dabbling in iOS app development.
This entry was posted in Tutorial and tagged , . Bookmark the permalink.

4 Responses to Tutorial: Building a Web Browser with UIWebView (Part 2)

  1. abha says:

    bt the url passed in textfield is not working.
    I mean ig I type http://www.google.com in the textfield it does not load that page. Actually it does nothing. Pls help me.

    • idz says:

      You need to follow the instructions in the “Making the Address Bar Work” section of the tutorial. If you did that and you are still having problems download the completed tutorial and compare your work with it.

  2. abha says:

    Also I wanna show the current URL in textfield. how to do that??

Leave a Reply