[localhost:~]$ cat * > /dev/ragfield

Tuesday, September 15, 2009

Insert text at the current cursor location in a UITextField on iPhone OS 3.0

The text widgets (UITextField, UITextView, etc) in the iPhone OS SDK appear to have been intentionally designed to allow as little control for 3rd party developers as possible. I found myself needing a user interface in an iPhone application which has buttons (in addition to the standard keyboard) that insert text into the currently selected UITextField. Neither UITextField nor any of it's parent classes or protocols have such a method.

One possible solution would be to get the contents of the UITextField, append the desired text to it, then set the contents of the UITextField to the new string. This gives the expected behavior if the text cursor is at the end of the text (which it usually is), but it does not give the correct behavior when the text cursor is anywhere else within the text.

There is a solution in iPhone OS 3.0. The method -(void)paste:(id)sender inserts the text from the system pasteboard at the current text cursor location. So all we need to do is temporarily hijack the system pasteboard. The basic steps are as follows:

  1. get a reference to the system pasteboard
  2. save the contents of the pasteboard so you can restore them later
  3. change the contents of the pasteboard to include the text you wish to insert
  4. send the -(void)paste:(id)sender message to the responder (UITextField or UITextView)
  5. restore the contents of the system pasteboard

Here is a simple category on UIResponder which adds a -(void)insertText:(NSString*)text method to this base class that should work on any text editing view.

@interface UIResponder(UIResponderInsertTextAdditions)
- (void) insertText: (NSString*) text;
@end

@implementation UIResponder(UIResponderInsertTextAdditions)

- (void) insertText: (NSString*) text
{
	// Get a refererence to the system pasteboard because that's
	// the only one @selector(paste:) will use.
	UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
	
	// Save a copy of the system pasteboard's items
	// so we can restore them later.
	NSArray* items = [generalPasteboard.items copy];
	
	// Set the contents of the system pasteboard
	// to the text we wish to insert.
	generalPasteboard.string = text;
	
	// Tell this responder to paste the contents of the
	// system pasteboard at the current cursor location.
	[self paste: self];
	
	// Restore the system pasteboard to its original items.
	generalPasteboard.items = items;
	
	// Free the items array we copied earlier.
	[items release];
}

@end