10.12. Web Views

Chapter 3 introduced the UITextView object and its hidden setHTML method for the creation of HTML-formatted windows. You can use the UIWebView class to build a browser-like page, providing many of the basic routines you'd find in a web browser: fetching pages remotely, navigating forward and back, and perform zooming and scaling. It is also useful for displaying rich text, using varying fonts and sizes. A web view can even detect phone numbers in web pages, allowing the user to tap them to initiate a phone call. Web views are one of the core components that make Safari tick. Web views can handle more than web pages, too; they can display images and PDFs. Web views can display any of these locally or remotely, based on the content you feed them.

10.12.1. Creating the Web View

The web view is created as any other UIView class is, using an initWithFrame method:

CGRect bounds = [ [ UIScreen mainScreen ] applicationFrame ];
UIWebView *webView =  [ [ UIWebView alloc ] initWithFrame: bounds ];

Once you have created it, you can set a few properties. To automatically scale the page to fit the screen, set the scalesPageToFit property to YES:

webView.scalesPageToFit = YES;

If you would like the web view to automatically detect phone numbers and allow the user to tap on them to dial, set the detectsPhoneNumbers property to YES:

webView.detectsPhoneNumbers = YES;

10.12.2. Displaying the Web View

To display the web view, anchor it to an existing window or view class:

[ self.view addSubview: webView ];

10.12.3. Loading Content

Once you have created the web view, you can load content a number of different ways. The most common way to load content is by using the loadRequest method to load a local or remote resource. The loadRequest method accepts an NSURLRequest object, which can be created from an existing NSURL object, which you've already learned about. An example to create and load a remote web page follows:

NSURL *url = [ NSURL URLWithString: @"http://www.oreilly.com" ];
NSURLRequest *request = [ NSURLRequest requestWithURL: url ];
[ webView loadRequest: request ];

To load a local file resource, use the NSURL class's fileURLWithPath initializer:

NSURL *url = [ NSURL fileURLWithPath: filePath ];
NSURLRequest *request = [ NSURLRequest requestWithURL: url ];
[ webView loadRequest: request ];

The UIWebView class also supports loading an NSString object as source. You may optionally provide a base URL to instruct the UIWebView object how to follow links and load remote resources:

[ webView loadHTMLString: myHTML
    baseURL: [ NSURL URLWithString: @"http://www.mywebsite.com" ]
];

10.12.4. Navigation

The UIWebView class manages browser navigation internally. You can control forward and back actions using the goForward and goBack methods, as shown below:

[ webView goBack ];
[ webView goForward ];

To reload existing content, use the web view's reload method:

[ webView reload ];

To cancel the loading of content, use the stopLoading method:

[ webView stopLoading ];

10.12.5. Delegate Methods

The web view class supports a set of UIWebViewDelegate delegate methods. These methods will be notified when certain events occur. To use these, assign a delegate to your web view:

webView.delegate = self;

The following delegate methods are notified by the web view. Each delegate method provides a pointer to the web view as its first parameter, allowing you to service multiple web views with a single delegate:



-(BOOL)webView:(UIWebView *)webView



shouldStartLoadWithRequest:(NSURLRequest *)request



navigationType:(UIWebViewNavigationType)navigationType;

Notified when the web view is instructed to load content. Should return YES to commence loading. The navigation type parameter provided refers to the origin of the request, and can be any one of the following:

UIWebViewNavigationTypeLinkClicked
UIWebViewNavigationTypeFormSubmitted
UIWebViewNavigationTypeBackForward
UIWebViewNavigationTypeReload
UIWebViewNavigationTypeFormResubmitted
UIWebViewNavigationTypeOther


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

Notified when the web view begins loading a request.



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

Notified when the web view finishes loading a request.



-(void)webView:(UIWebView *)webView



didFailLoadWithError:(NSError *)error;

Notified if an error occurs in the loading of a request. An NSError object is provided to identify the type of error that has occurred.

10.12.6. WebDemo: Google Search Utility

This example uses a UIWebView to display the results of a Google search. Enter the search terms into a UIView class named UISearchBar, which is a simple view class for accepting search input. Unfortunately, Apple has privatized the search bar's underlying UISearchField, which Safari uses to display both an address field and a search field within the same navigation bar. In this example, the user will enter search criteria and press the Search button. This will invoke a query to Google based on the input provided and will display the output in the web view (Figure 10-8).

Figure 10-8. WebDemo example


You can compile this application, shown in Examples Example 10-34 through Example 10-38, with the SDK by creating a view-based application project named WebDemo. Be sure to pull out the Interface Builder code if you'd like to see how all objects are created from scratch.

Example 10-34. WebDemo application delegate prototypes (WebDemoAppDelegate.h)
#import <UIKit/UIKit.h>

@class WebDemoViewController;

@interface WebDemoAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    WebDemoViewController *viewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet WebDemoViewController *viewController;

@end

                                          

Example 10-35. WebDemo application delegate (WebDemoAppDelegate.m)
#import "WebDemoAppDelegate.h"
#import "WebDemoViewController.h"

@implementation WebDemoAppDelegate

@synthesize window;
@synthesize viewController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    CGRect screenBounds = [ [ UIScreen mainScreen ] bounds ];

    self.window = [ [ [ UIWindow alloc ] initWithFrame: screenBounds ] autorelease ];
    viewController = [ [ WebDemoViewController alloc ] init ];

    [ window addSubview: viewController.view ];
    [ window makeKeyAndVisible ];
}


- (void)dealloc {
    [ viewController release ];
    [ window release ];
    [ super dealloc ];
}


@end

                                          

Example 10-36. WebDemo view controller prototypes (WebDemoViewController.h)
#import <UIKit/UIKit.h>

@interface WebDemoViewController : UIViewController <UISearchBarDelegate> {
    UISearchBar *searchBar;
    UIWebView *webView;
}

@end

Example 10-37. WebDemo view controller (WebDemoViewController.m)
#import "WebDemoViewController.h"

@implementation WebDemoViewController

- (id)init {
    self = [ super init ];
    if (self != nil) {

    }
    return self;
}

- (void)loadView {
    [ super loadView ];
    CGRect bounds = [ [ UIScreen mainScreen ] applicationFrame ];

    searchBar = [ [ UISearchBar alloc ] initWithFrame:
        CGRectMake(0.0, 0.0, bounds.size.width, 48.0) ];
    searchBar.delegate = self;
    searchBar.placeholder = @"Google";
    [ self.view addSubview: searchBar ];

    webView = [ [ UIWebView alloc ] initWithFrame:
        CGRectMake(0.0, 48.0, bounds.size.width, bounds.size.height - 48.0) ];
    webView.scalesPageToFit = YES;
    [ self.view addSubview: webView ];
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)activeSearchBar {
    NSString *query = [ searchBar.text
        stringByReplacingOccurrencesOfString: @" " withString: @"+" ];
    NSURL *url = [ NSURL URLWithString:
        [ NSString stringWithFormat: @"http://www.google.com/search?q=%@", query ] ];
    NSURLRequest *request = [ NSURLRequest requestWithURL: url ];
    [ webView loadRequest: request ];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)
interfaceOrientation {

    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)didReceiveMemoryWarning {
    [ super didReceiveMemoryWarning ];
}

-   (void)dealloc {
    [ searchBar release ];
    [ webView release ];
    [ super dealloc ];
}

@end

                                          

Example 10-38. WebDemo main (main.m)
#import <UIKit/UIKit.h>

int main(int argc, char *argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"WebDemoAppDelegate");
    [pool release];
    return retVal;
}

10.12.7. What's Going On

  1. When the application instantiates, its application delegate builds a view controller and attaches it to a window, as usual. The view controller is initialized, which causes UISearchBar and UIWebView objects to be created. The view controller is assigned as the delegate for the search bar.

  2. When the user submits a set of search terms, the search bar notifies its delegate's searchBarSearchButtonClicked method. The method formats a Google URL based on the terms provided and builds an NSURLRequest object. The object is then handed to the web view when its loadRequest method is invoked.

  3. The web view's internal plumbing handles the entire process of fetching and displaying the web page, scrolling, and clicking on links.

10.12.8. Further Study

Web views are very easy to implement and look great. Try a few other activities before moving on:

  • Try loading your own web content into a web view using the loadHTMLString method.

  • Add a navigation controller with a toolbar. Add functional forward, back, stop, and reload buttons to the toolbar.

  • Replace the UISearchBar with a UINavigationBar. Add a UITextField object as a subview and change the code to act like the address bar of a browser.

  • Check out the UIWebView.h and UISearchBar.h prototypes. You'll find these deep within /Developer/Platforms/iPhoneOS.platform, inside the UI Kit framework's Headers directory.