dcsimg

Custom Controls for the iPhone

Building a scrollable, dynamic user interface for iPhone.

Custom classes

To accomplish this task, I have created two new classes. The first class is used as a scrollable background and is implemented in a class named LMScrollView. This class subclasses the UIScrollView class as defined in LMScrollView.h.

#import <UIKit/UIKit.h>

@interface LMScrollView : UIScrollView {

}

@end

Our implementation is fairly straight forward in the implementation file LMScrollView.m.


#import "LMScrollView.h"

@implementation LMScrollView

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // Initialization code
		self.backgroundColor = [UIColor greenColor];
		self.scrollEnabled = YES;
		self.scrollsToTop = YES;
		self.contentSize = CGSizeMake(320,1000);  // arbitrary "height" of 1000 pixels
		self.showsVerticalScrollIndicator = YES;
		self.bounces = YES;
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    // Drawing code
}

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

@end

LMScrollView is setup with some basic charateristics including scroll behavior and dimensions. We also set the background color to a somewhat obnoxious green. The height of 1000 pixels is arbitrary and needs some more thought on properly setting the size — for example, there is no need to scroll the screen if there are only a few fields.

The other class created is named LMEditField. The purpose of this class is to allow the programmer to get a simple set of functionality wrapped up into a single class.

This class supports an static label (UILabel) and a text field (UITextField) for capturing input. By wrapping things up in a class we can encapsulate a bunch of setup and configuration automatically without having to repeat it for each field that is created dynamically. This lets the application programmer focus on the application elements and not get bogged down with details of each field. This class is defined in LMEditField.h.

#import <UIKit/UIKit.h>

@interface LMEditField : UIView <UITextFieldDelegate>{
	UILabel * label;
	UITextField * txt;
}
-(void)setup:(NSString *) lbl defaultValue:(NSString *)dv;
-(NSString *) getValue;
@end

We can see that the two member variables representing the UI elements are defined along with three methods. The setup and getValue methods are used by the programmer to set the field’s values and to retrieve the values respectively. This class is implemented in the file named LMEditField.m.


#import "LMEditField.h"

@implementation LMEditField

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // Initialization code
    }
    return self;
}

-(BOOL)textFieldShouldReturn:(UITextField *) theTextField {
	[theTextField resignFirstResponder];
	return YES;
}

-(NSString *) getValue
{
	return txt.text;
}
-(void)setup:(NSString *) lbl defaultValue:(NSString *)dv  {
	CGRect bounds = self.bounds;
	label = [[UILabel alloc] initWithFrame:CGRectMake(0,0,bounds.size.width /2,bounds.size.height)];
	[label setText:lbl];
	[self addSubview:label];
	txt = [[UITextField alloc] initWithFrame:CGRectMake(bounds.size.width / 2,0,bounds.size.width/2,bounds.size.height)];
	[txt setText:dv];
	txt.textAlignment = UITextAlignmentRight;
	txt.backgroundColor = [UIColor yellowColor];
	txt.font = [UIFont systemFontOfSize:20];
	[txt setReturnKeyType:UIReturnKeyDone];
	[txt setEnablesReturnKeyAutomatically:YES];
	txt.delegate = self;
	[self addSubview:txt];

}

- (void)drawRect:(CGRect)rect {
    // Drawing code
	NSLog(@"lmeditfield draw");
}

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

@end

The method named setup does most of the heavy lifting as it creates a label and edit field which each take up 50% of the LMEditField’s allocated horizontal dimension. The UITextField’s background is set to yellow, to go along with the green background, of course. Other things are setup such as font size and a call to setup the delegate of the UITextField, which allows the on screen keyboard to disappear when the user hits the enter key. Handling the keyboard’s visibility is a surprisingly important aspect to iPhone development. Note the method named textFieldShouldReturn which sends the message resignFirstResponder to the relevant UITextField.

Now that our toolbox is more or less ready, it is time to demonstrate its use.

Wiring things up

In the application I am porting to iPhone, the list of the required fields comes from an XML feed downloaded via HTTP. However for our purposes here the application demonstrates the creation and handling of just two fields, first and last name.

First, let’s look at the interface definition of iDGUIViewController where we define some fields statically. Again, in a more completely dynamic approach, these elements would be implemented as some sort of collection, linked list, or array.


#import <UIKit/UIKit.h>
#import "LMScrollView.h"
#import "LMEditField.h"

@interface iDGUIViewController : UIViewController {
	LMScrollView * contentView;
	int txtVOffset;
	UIButton * btnSubmit;
	LMEditField * firstName;
	LMEditField * lastName;

}

@end

Here are the two methods of interest in the implementation of the view controller. These are found in the file named iDGUIViewController.m.


// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {

	CGRect screenRect = CGRectMake(0,0,320,480);
	contentView = [[LMScrollView alloc] initWithFrame:screenRect];

	btnSubmit= [UIButton buttonWithType:UIButtonTypeRoundedRect];
	[btnSubmit setBounds:CGRectMake(50,50,100,100)];
	[btnSubmit setTitle:@"Hit Me!" forState:UIControlStateNormal];
	[btnSubmit setTitle:@"Hit Me!" forState:UIControlStateHighlighted];
	btnSubmit.center = CGPointMake(160,240);
	[btnSubmit addTarget:self action:@selector(hitbutton:) forControlEvents:UIControlEventTouchUpInside];
	[contentView addSubview:btnSubmit];

	txtVOffset = 50;
	firstName = [[LMEditField alloc] initWithFrame:CGRectMake(5,txtVOffset,310,40)];
	[firstName setup:@"First Name:" defaultValue:@"Frank"];
	[contentView addSubview:firstName];

	txtVOffset += 50;
	lastName = [[LMEditField alloc] initWithFrame:CGRectMake(5,txtVOffset,310,40)];
	[lastName setup:@"Last Name:" defaultValue:@"Ableson"];
	[contentView addSubview:lastName];

	self.view = contentView;
	[contentView release];

}

- (void)hitbutton: (UIButton *) b
{
	NSString * t = [[NSString alloc] initWithFormat:@"%@ %@",[firstName getValue],[lastName getValue]];
	NSLog([[NSString alloc] initWithFormat:@"button hit! [%@]",t]);
//	printf("button hit! [%s]\n",[t cString]);
}

There are a bunch of hard-coded things here which should also be transformed to be more dynamic. For example, everything here assumes a “portrait” orientation, but it follows that this layout could be built to support either orientation. Note the use of the variable txtVOffset which keeps track of how far “down” the screen a particular control should be placed.

The hitbutton method is invoked when the user … hits the button. Note that I have left the call in here to printf — because sometimes it is refreshing to see an old friend!

Here is a screen shot of the application.

iDGUI app in action
iDGUI app in action

I warned you, it isn’t a very pretty application at present, but that gentle reader, is an exercise left to you. I hope this is of some value to you.

Fatal error: Call to undefined function aa_author_bios() in /opt/apache/dms/b2b/linux-mag.com/site/www/htdocs/wp-content/themes/linuxmag/single.php on line 62