10.11. Scroll Views

Think of scroll views as one of those red secret decoder slides you find in cereal boxes. Placing this small red flap of plastic over part of a secret codebook reveals a small portion of the page. The rest of the page is still there, but you can't see it until you slide the lens over it. The red lens represents the iPhone's screen, and reveals only the content the user has scrolled over. The rest of the content is hidden from view, falling off the screen, until the user scrolls the window to the part he wants to see. Scroll views not only allow you to scroll content, but to zoom in and out, and even page flip.

10.11.1. Creating the Scroll View

The UIScrollView class is responsible for all UI Kit-based scrolling. Creating a scroll view is the equivalent of creating both a red lens and blank pages in a secret codebook:

 

CGRect bounds = [ [ UIScreen mainScreen ] applicationFrame ];
UIScrollView *scrollView = [ [ UIScrollView alloc ] initWithFrame: bounds ];

                                          

Once you have created the scroll view, you'll glue the content of another view onto the scroll view's blank pages. This creates a scrolling content window:

[ scrollView addSubview: myBiggerView ];

You must provide the content's actual size to the scroll view so that it knows how much to scroll:

scrollView.contentSize = myBiggerView.frame.size;

To enable zooming in or out, adjust the scroll view's maximumZoomScale and minimumZoomScale properties. This will allow the user to pinch and resize the content:

 

scrollView.maximumZoomScale = 3.00; /* Allow zooming in to 3x original size */
scrollView.minimumZoomScale = 0.25; /* Allow zooming out to 25% of original size */

                                          

To enable zooming, you'll also need to add a UIScrollViewDelegate delegate that responds to a method named viewForZoomingInScrollView. This method returns the UIView object to use when zooming content:

scrollView.delegate = self;
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return myBiggerView;
}

NOTE

 

For large data sizes, you'll want to start off with a zoom scale below actual size (1.0) to allow the user to zoom in smoothly.

10.11.2. Properties

In addition to the basic properties just outlined, scroll views have many other properties, which can fine-tune the behavior of your content. You can customize the UIScrollView class in many ways. The following properties are the most commonly used:



indicatorStyle

Specifies the type of scrollbar indicators you'd like to use. The default behavior is to draw black scroll bars with a white border, which works against most backgrounds. The following styles are available:

UIScrollViewIndicatorStyleDefault
UIScrollViewIndicatorStyleBlack
UIScrollViewIndicatorStyleWhite


contentOffset

A CGPoint structure containing the offset of the content to display in the upper-left corner of the window. The default is to begin at 0x0, but you may position your content differently.



directionalLockEnabled

The default behavior is to allow the user to scroll both horizontally and vertically simultaneously. Set this property to YES to cause the behavior to lock the user into either horizontal or vertical scrolling, depending on the initial gesture.



bounces

When the user reaches the edge of the scrollable region, this feature allows the user to drag slightly beyond the boundaries. When user lifts his finger, the region will bounce back into place like a rubber band, giving the user a visual cue that he's reached the beginning or end of the document. If you don't want the user to be able to scroll past the viewable content, set this property to NO.



bouncesZoom

Like the bounces option, this method allows the user to zoom beyond the minimum or maximum zoom levels, then bounces the user back to within range. If you don't want the user to be able to zoom past the ranges you've specified, set this property to NO.



pagingEnabled

When paging is enabled, the scroll view is split up into separate segments and the user's scrolling experience will be that of flipping pages. You can use this to perform page flicking, explained in Chapter 13.

10.11.3. Delegate Methods

When a delegate is assigned to the scroll view, the following delegate methods are notified during special events:



-(void)scrollViewDidScroll:(UIScrollView *)scrollView;

Notified when the view is scrolled. Includes a pointer to the scroll view that was scrolled, at which point its contentOffset property can be read to determine where it is scrolled to.



-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;

Notified when the user first begins dragging in any direction. This, too, can be used to read the contentOffset property of the scroll view, whose pointer is passed in as an argument.



-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;

Notified when the user lifts a dragging finger. A Boolean value is also provided indicating whether the scroll view will need to decelerate before reporting a final resting position.



-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;

Notified when the user lifts his finger up as the scroll view continues to move. This can be used to read the contentOffset property to identify specifically where the user last scrolled to before lifting his finger, even though this will not be the final resting position of the scroll bars.



-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

Notified when the above deceleration completes and the scroll view ceases scrolling. By the time this notification is received, the scroll view's contentOffset property will reflect the final resting position of the scroll bar.



-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale;

Notified when the user has zoomed to a given magnification. The scale, represented in a floating-point value, will be passed as an argument.



-(BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;



-(void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;

When the user taps on the iPhone's status bar, the scroll view delegate can determine if the view should scroll back to the top.

10.11.4. BigImage: Scrolling a Weather Map

This example uses the NSData object you've learned about to download a large weather map and display it to the user in a scroll view. You'll see how another UIView class (UIImageView) is attached to scroll view, and how its delegate works.

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

Example 10-29. BigImage application delegate prototypes (BigImageAppDelegate.h)

 

#import <UIKit/UIKit.h>

@class BigImageViewController;

@interface BigImageAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    BigImageViewController *viewController;
}

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

@end

                                          

Example 10-30. BigImage application delegate (BigImageAppDelegate.m)

 

#import "BigImageAppDelegate.h"
#import "BigImageViewController.h"

@implementation BigImageAppDelegate

@synthesize window;
@synthesize viewController;


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

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

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


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


@end

                                          

Example 10-31. BigImage view controller prototypes (BigImageViewController.h)

 

#import <UIKit/UIKit.h>

@interface BigImageViewController : UIViewController <UIScrollViewDelegate> {
    UIScrollView *scrollView;
    UIImageView *imageView;
}

@end

                                          

Example 10-32. BigImage view controller (BigImageViewController.m)

 

#import "BigImageViewController.h"

@implementation BigImageViewController

- (id)init {
    self = [ super init ];
    if (self != nil) {
        imageView = [ [ UIImageView alloc ] initWithImage:
            [ UIImage imageWithData:
            [ NSData dataWithContentsOfURL:
               [ NSURL URLWithString:
                  @"http://forecast.weather.gov/wwamap/png/US.png" ]
            ]
        ] ];
    }
    return self;
}

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

    scrollView = [ [ UIScrollView alloc ] initWithFrame: bounds ];
    scrollView.contentSize = imageView.frame.size;
    scrollView.maximumZoomScale = 3.0;
    scrollView.minimumZoomScale = 0.25;
    scrollView.delegate = self;
    scrollView.bounces = NO;
    [ scrollView addSubview: imageView ];

    self.view = scrollView;
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return imageView;
}

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

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

- (void)dealloc {
    [ UIScrollView release ];
    [ UIImageView release ];
    [ super dealloc ];
}

@end

                                          

Example 10-33. BigImage main (main.m)

 

#import <UIKit/UIKit.h>

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

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

                                          

10.11.5. What's Going On

  1. When the application is run, its application delegate builds a view controller and attaches it to a window, as usual. The view controller is initialized, which causes a UIImageView object to be created. The contents of the image view are downloaded from the national weather service.

  2. When the view controller is loaded, a UIScrollView object is created. The image view is anchored to the scroll view and the scroll view's zooming and aesthetic properties are set.

  3. The scroll view's internal plumbing handles the entire scrolling process, scroll bar display, and other related functions.

  4. When the user zooms, the scroll view's delegate method viewForZoomingInScrollView is called. This returns the same UIImageView object, since we don't have a higher resolution copy to work with.

10.11.6. Further Study

Scroll views are an easy way to scale down large data presented to the user:

  • Try your hand at creating scroll views for some of your own content.

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