Custom Controls for the iPhone

Building a scrollable, dynamic user interface for iPhone.

Formula for a Dynamic UI

When I first began writing applications for iPhone I had a bit of a learning curve with the Interface Builder tool.

Interface Builder is the stock mechanism for wiring up iPhone user interface elements with the code which implements various functionality.

Drop a control on a view. Click, drag. Setup messages. IBOutlets. Assign delegates. Navigate the world of “File’s Owner”, “First Responder”, etc. It works, but I guess I’m still a bit old-school and enjoy the declarative nature of being able to read a bunch of text files to see what is going on.

I am currently porting a BlackBerry application to iPhone which requires a flexible collection of simple user interface elements that is built at run time based on data downloaded from a remote server. Because of this dynamic nature of the fields, I need a solution other than using design-time tools such as Interface Builder.

If this sounds familiar, you probably read an earlier article where we had a look at building a dynamic user interface for Android applications — this week we have a look at a similar recipe for a scrollable screen for capturing input in an iPhone application.

iDGUI application

The name of this simple application is iDGUI, short for Dynamic GUI. The i is in front because somewhere it is written that you’re supposed to do that for all iPhone apps. Kidding.

The application was created in Xcode, built for the latest sdk, but the specific SDK level should not matter — we’re using pretty fundamental CocoaTouch code. The project started out as a “View based application” which was then slightly modified.

The Xcode View based application template includes a single Window and ViewController as well as a nib file which is ordinarily used by developers in the Interface Builder tool. The nib file is not touched — we work directly with the code.

As a very quick refresher, each class in Objective-C is ordinarily implemented across two files. There is a header file (classname.h) and an implementation file (classname.m). A stock view-based application contains two classes:

  • iDGUIAppDelegate, implemented in iDGUIAppDelegate.h and iDGUIAppDelegate.m
  • iDGUIViewController, implemented in iDGViewController.h and iDGUIViewController.m

In addition to these classes the stock entry point for a CocoaTouch application is in the file main.m which is responsible for boot-strapping the application via a call to UIApplicationMain().

#import <UIKit/UIKit.h>

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

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

The class iDGUIAppDelegate implements the protocol named UIApplicationDelegate.


#import <UIKit/UIKit.h>

@class iDGUIViewController;

@interface iDGUIAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    iDGUIViewController *viewController;
}

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

@end

The relevant code here is in the method named applicationDidFinishLaunching which sets up the relationship between the window and the view controller and then makes the window visible.


#import "iDGUIAppDelegate.h"
#import "iDGUIViewController.h"

@implementation iDGUIAppDelegate

@synthesize window;
@synthesize viewController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {    

    // Override point for customization after app launch
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
}

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

@end

}

The two @synthesize statements do some magic to initialize the window and viewController variables.

The viewController can be initialized in generally one of two means.

If our application is using InterfaceBuilder and the nib file to handle layout and event wiring, we want to implement the method named initWithNibName which “inflates” the UI created at design-time.

Alternatively, to build things at “run time”, we want to implement the loadView method, which is what we’re going to have a look at in this article.

Before jumping into the loadView method, let’s take a quick detour to talk about what we hope for our application to accomplish. Our goals are rather modest at present — the application needs to present one or more data input fields, each with a descriptive label. We also want a button for the user to be able to “submit” their data. For our purposes, we’re going to build a dynamic GUI with two fields, first and last name.

Because we want our application to be able to handle an arbitrary number of fields, we need some sort of strategy for scrolling the screen. Two immediate ideas come to mind.

We can put each field’s “label” and non-editable value into a scrollable table. When the user selects an entry we can push a screen onto the “ui stack” to handle the editing of that field, returning to the list when the editing of each field is complete.

Alternatively we can build a single user interface which scrolls vertically to accommodate the required fields, with each field immediately editable so the user doesn’t have to transition to a different screen for each element.

An argument can be made for both design patterns. I have chosen the latter approach as it allows us to focus more directly on creating UI elements at runtime and less on MVC design patterns.

Next: Custom Classes

Comments on "Custom Controls for the iPhone"

jpurdy

Great Article

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>