Text Helper

In the app I’m currently building, there are many longish text fields that can be edited. I decided to create a little utility class to handle the presentation of an editing interface for these fields, and I’d like to share it with you now.

The Goal

display viewdisplay viewWhat we’re aiming for is something like the sequence of screens you see in the “notes” section of the iPhone “Contacts” app. First (as you can see to the left) you’re given a non-editable “display” view; when you tap on that view, an editable view slides in from the right. I wanted to create a class that made it as easy as possible to generate those editable views.

NIB

I used Interface Builder to lay out a simple NIB for my class. I’m making it available here; I hope it’s viewable in the tools you’re using. In case it’s not, here’s a brief description of it.

The NIB’s “File’s Owner” is a TextEdit object. (The TextEdit class is defined in the next section.) It contains only 3 UI objects: Its base (320×460) UIView contains two child views: A (320×200) UIImageView at (0, 0), and a (282×160) UITextView at (19, 22). The UIImageView contains this image; combined with the (carefully tuned) positioning of the UITextView, it creates the illusion that the user is looking at a UITableView. The TextEdit's view outlet is connected to the UIView, and its textView outlet is connected to the UITextView.

At this point, you might wonder why I went to the trouble of faking up a table-like look, rather than simply using a one-cell table. The answer is that, for reasons which are as yet obscure to me, the keyboard doesn’t work quite right in that case. If you create a view controller, put a UITextView inside a table cell in that controller’s view, make that UITextView the first responder, and then push the new controller onto a Navigation stack, the keyboard does not scroll in from the right; it pops into view immediately. That’s ugly, hence this workaround.

Code

The class itself is delightfully brief. Here’s the header:

#import <UIKit/UIKit.h>


@interface TextEdit : UIViewController
{
	id			object;
	NSString*		keyPath;
	
	UITextView*		textView;
}

@property (nonatomic, retain) id object;
@property (nonatomic, retain) NSString* keyPath;

@property (nonatomic, retain) IBOutlet UITextView* textView;

@end

and here’s the implementation:

#import "TextEdit.h"


@interface TextEdit ()

- (void)save;
- (void)dismiss;

@end


@implementation TextEdit

@synthesize object;
@synthesize keyPath;
@synthesize textView;


- (void)viewDidLoad
{
	[super viewDidLoad];

	// Add buttons
	self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismiss)] autorelease];
	self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(save)] autorelease];

	// Initialize display
	textView.text = [object valueForKeyPath:keyPath];

	// Display KB
	[textView becomeFirstResponder];
}


- (void)dealloc
{
	[object release];
	[keyPath release];
	[textView release];
	[super dealloc];
}

#pragma mark Extension methods

- (void)save
{
	[object setValue:textView.text forKeyPath:keyPath];
	[self dismiss];
}


- (void)dismiss
{
	[self.navigationController popViewControllerAnimated:YES];
}

@end

Usage

This class is designed to allow the editing of an NSString property of a Key-Value Coding compliant object. It expects that it will be pushed onto a UINavigationController's stack for display. Here’s an example of how it might be used to edit the “desc” field of an object, which holds some sort of a “Description”:

- (void)editDescription
{
	// Create a new controller
	TextEdit* te = [[TextEdit alloc] initWithNibName:@"TextEdit" bundle:nil];
	
	// Configure the new controller
	te.title = @"Description";
	te.object = someObject;
	te.keyPath = @"desc";
	
	// Present the "edit" controller
	[self.navigationController pushViewController:te animated:YES];
	
	// Clean up
	[te release];
}

The parent view controller (of which editDescription would be a method) should use Key-Value Observing to update its views to reflect changes made to someObject by the TextEdit view controller.

Caveats

The biggest shortcoming of this class lies in its handling of its object and keyPath properties; the class assumes that these properties are set before the view is loaded, and that they do not change during the life of the view controller. This is a little sloppy, but I don’t anticipate it causing any difficulty for my purposes. YMMV.

Share and Enjoy:
  • Twitter
  • Facebook
  • Digg
  • Reddit
  • HackerNews
  • del.icio.us
  • Google Bookmarks
  • Slashdot
This entry was posted in iPhone. Bookmark the permalink.