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
What 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.
Pingback: Things that were not immediately obvious to me » Blog Archive » Date Helper
Pingback: Things that were not immediately obvious to me » Blog Archive » Sliding Keyboards