Resources : Blog

iPhone UITextField Tutorial: Handling Keyboard Interactions

By Ashish Khadse in iPhone - iPad

February 17, 2010

< All >

This post is written to provide you with the process to get the return button working on the keypad that pops up while filling a text field, the “Background Tap” functionality, and also what to do when the text field hides behind the keypad.

First we make a demo View-based Application for this, say “BackgroundTapForBlog” .
Add a text field to BackgroundTapForBlogViewController.xib, declare it in your BackgroundTapForBlogViewController.h file ,say tfUsername and link them in .xib.

Return Button on KeyPad:

Once you are done with this, add a function “textFieldDoneEditing” to the BackgroundTapForBlogViewController.m file, and do not forget to declare it in the BackgroundTapForBlogViewController.h file. This function gets rid of the keypad once you are done filling in the textfield.

BackgroundTapForBlogViewController.h file -
[objc highlight=”3,5,6,7″]
#import &lt;UIKit/UIKit.h&gt;
@interface BackgroundTapForBlogViewController: UIViewController{
UITextField *tfUsername;
}
@property(nonatomic, retain) IBOutlet UITextField *tfUsername;
-(IBAction) textFieldDoneEditing : (id) sender;
-(IBAction) backgroundTap:(id) sender;
@end
[/objc]

BackgroundTapForBlogViewController.m file -
[objc highlight=”4,7,11,15,16,17,19,20,21″]
#import &quot;BackgroundTapForBlogViewController.h&quot;

@implementation BackgroundTapForBlogViewController
@synthesize tfUsername;

– (void)viewDidUnload {
self.tfUsername = nil;
}

– (void)dealloc {
[tfUsername release];
[super dealloc];
}

-(IBAction) textFieldDoneEditing : (id) sender{
[sender resignFirstResponder];
}

-(IBAction) backgroundTap:(id) sender{
[self.tfUsername resignFirstResponder];
}
@end
[/objc]

Now, save your project (Command+S).
Finally, open BackgroundTapForBlogViewController.xib again and link the “textFieldDoneEditing” function from File’s Owner to your text field/fields, and select “DidEndOnExit” option.
Linking textFieldDoneEditing

Background Tap Functionality:

Other than the return button on the keypad, we do provide an option that the keypad should disappear if the user touches the background. This is done as follows –
Now go back to Xcode and declare a function “backgroundTap” in the BackgroundTapForBlogViewController.h file and add it to BackgroundTapForBlogViewController.m file.

[objc]
-(IBAction) backgroundTap:(id) sender{
[self.tfUsername resignFirstResponder];
}
[/objc]

This function gets rid of the keypad. ResignFirstResponder notifies the receiver(in this case, tfUsername) that it is supposed to give up its status as first responder in the current window.
Save your project (Command+S).
Now, open BackgroundTapForBlogViewController.xib. Select UIView from the Main Window of Interface Builder and press Command+2 (open Connection Inspector). You will notice there is no option like touch up inside. So you need to change the class from UIView to UIControl in Identity Inspector (Command + 4). UIView is extended from UIControl, now events like touch up inside can be detected on a UIControl. Hence, this change.
Then select File’s Owner and link the function “backgroundTap” to the background of your view, and select option “Touch Up Inside” with UIControl.
Connecting backgroundTap function

Text Field Hiding behind keypad:

When the text field/fields begin hiding behind the keypad, it becomes necessary to scroll up so that the text field would be visible while filling it from the keypad.
For this, we need to include 5 files viz.,
MIBackgroundTapDelegate.h,
MIScrollView.h
MIScrollView.m
ScrollableViewController.h
ScrollableViewController.m

Add these files to your project, and follow the instructions –

BackgroundTapForBlogViewController.h –
Extend our controller from “ScrollableViewController”. We no longer need a declaration for backgroundTap function, since we are implementing MIBackgroundTapDelegate which has a declaration for the same.

[objc highlight=”2,3,5,10″]
#import &lt;UIKit/UIKit.h&gt;
#import &quot;ScrollableViewController.h&quot;
#import &quot;MIBackgroundTapDelegate.h&quot;

@interface BackgroundTapForBlogViewController:ScrollableViewController &lt;MIBackgroundTapDelegate&gt; {
UITextField *tfUsername;
}
@property(nonatomic, retain) IBOutlet UITextField *tfUsername;
-(IBAction) textFieldDoneEditing : (id) sender;
//-(IBAction) backgroundTap:(id) sender;
@end
[/objc]

BackgroundTapForBlogViewController.m file-

[objc highlight=”6,7″]
#import &quot;BackgroundTapForBlogViewController.h&quot;

@implementation BackgroundTapForBlogViewController
@synthesize tfUsername;
– (void)viewDidLoad {
self.svScrollViewM.contentSize = CGSizeMake(320,416);
[self registerForEditingEvents:tfUsername];
[super viewDidLoad];
}

– (void)viewDidUnload {
self.tfusername = nil;
}
– (void)dealloc {
[tfUsername release];
[super dealloc];
}
-(IBAction) textFieldDoneEditing : (id) sender{
[sender resignFirstResponder];
}
-(IBAction) backgroundTap:(id) sender{
[self.tfUsername resignFirstResponder];
}
@end
&lt;/objc&gt;

&lt;b&gt;MIBackgroundTapDelegate.h -&lt;/b&gt;
We declare a protocol for backgroundtap function.

[objc]
@protocol MIBackgroundTapDelegate
– (IBAction)backgroundTap:(id)sender;
@end
[/objc]

ScrollableViewController.h -
Declare properties and functions for the scroll view controller.

[objc]
#import

@interface ScrollableViewController : UIViewController {
UIControl * ctrlKeyboardFocusFieldM;
BOOL bKeyboardShownM;
UIScrollView * svScrollViewM;
}

@property (nonatomic, retain) UIControl * ctrlKeyboardFocusFieldM;
@property (nonatomic, retain) IBOutlet UIScrollView * svScrollViewM;

– (void) registerForEditingEvents:(UIControl *) aControl;
– (void) registerForKeyboardNotifications;
– (void) keyboardWasHidden:(NSNotification*)aNotification;
– (void) keyboardWasShown:(NSNotification*)aNotification;
– (void) textFieldDidBeginEditing:(UITextField *)textField;
– (void) textFieldDidEndEditing:(UITextField *)textField;
@end
[/objc]

ScrollableViewController.m -
[objc]
#import &quot;ScrollableViewController.h&quot;
@implementation ScrollableViewController
@synthesize ctrlKeyboardFocusFieldM;
@synthesize svScrollViewM;
– (void)viewDidLoad {
[self registerForKeyboardNotifications];
[super viewDidLoad];
}
– (void)didReceiveMemoryWarning {
// Releases the view if it doesn’t have a superview.
[super didReceiveMemoryWarning];
}
– (void)viewDidUnload {
self.ctrlKeyboardFocusFieldM = nil;
self.svScrollViewM = nil;
}
– (void)dealloc {
[ctrlKeyboardFocusFieldM release];
[svScrollViewM release];
[super dealloc];
}
– (void)registerForKeyboardNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasHidden:)
name:UIKeyboardDidHideNotification object:nil];
}

// Called when the UIKeyboardDidShowNotification is sent.
– (void)keyboardWasShown:(NSNotification*)aNotification{
if (bKeyboardShownM)
return;

NSDictionary* info = [aNotification userInfo];

// Get the size of the keyboard.
NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;

// Resize the scroll view (which is the root view of the window)
CGRect viewFrame = [self.svScrollViewM frame];
viewFrame.size.height -= keyboardSize.height;
self.svScrollViewM.frame = viewFrame;

// Scroll the active text field into view.
CGRect textFieldRect = [self.ctrlKeyboardFocusFieldM frame];
[self.svScrollViewM scrollRectToVisible:textFieldRect animated:YES];
bKeyboardShownM = YES;
}

// Called when the UIKeyboardDidHideNotification is sent
– (void)keyboardWasHidden:(NSNotification*)aNotification{
NSDictionary* info = [aNotification userInfo];

// Get the size of the keyboard.
NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;

// Reset the height of the scroll view to its original value
CGRect viewFrame = [self.svScrollViewM frame];
viewFrame.size.height += keyboardSize.height;
self.svScrollViewM.frame = viewFrame;
bKeyboardShownM = NO;
}

– (void)textFieldDidBeginEditing:(UITextField *)textField{
self.ctrlKeyboardFocusFieldM = textField;
}

– (void)textFieldDidEndEditing:(UITextField *)textField{
self.ctrlKeyboardFocusFieldM = nil;
}

– (void) registerForEditingEvents:(UIControl*)aControl{
[aControl addTarget:self action:@selector(textFieldDidBeginEditing:)
forControlEvents:UIControlEventEditingDidBegin];
[aControl addTarget:self action:@selector(textFieldDidEndEditing:)
forControlEvents:UIControlEventEditingDidEnd];
}
@end
[/objc]

1.registerForKeyboardNotifications function is used to set notifications whenever keyboard is shown or hidden, and it accordingly, calls selector methods keyboardWasShown or keyboardWasHidden respectively.
2.In keyboardWasShown function, we obtain the keyboard frame size, and resize it from the scroll view’s frame size (which is equivalent to shifting the scroll upwards).Accordingly, we also move the active text field to a location above the keyboard so as to make it visible.
3.In keyboardWasHidden function, we add the keyboard size to the current frame size, to obtain the original size, and it also move the active textfield to its original position.

MIScrollView.h -
[objc]
#import
#import &quot;MIBackgroundTapDelegate.h&quot;

@interface MIScrollView : UIScrollView {
id backgroundTapDelegate;
}

@property (nonatomic, retain) idbackgroundTapDelegate;
@end
[/objc]

MIScrollView.m -
[objc]
#import &quot;MIScrollView.h&quot;
#import &quot;MIBackgroundTapDelegate.h&quot;

@implementation MIScrollView
@synthesize backgroundTapDelegate;

-(void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event {
if(backgroundTapDelegate) {
[backgroundTapDelegate backgroundTap: self];
}
}
@end
[/objc]

In the BackgroundTapForBlogViewController.xib, add a scrollview, move everything on top of the scrollview and resize it as per requirement. In its Identity Inspector(Command+4), change its class to MIScrollView.
Link this scrollview to svScrollViewM of File’s Owner.
Linking scrollview

Link delegate and backgroundTapDelegate of MIScrollView to File’s Owner.
Linking Delegates of scrollview

Now, save your application in Xcode, and press Build & Go. When you select the textfield, the output would look like this –
Frame resized

You can download the source code from here.

  • Animesh

    Superb!!!

  • Mohd Iftekhar Qurashi

    You can use Keyboard Manager to fix this issue with just **one line of code**. It also **support device orientation**. This is **universal** also.

    Download demo project here
    https://github.com/hackiftekhar/IQClasses/tree/master/KeyboardTextFieldDemo

    Just drag and drop **KeyboardManager** and **SegmenedNextPrevious** classes to your project.
    In your appDelegate write only one line of code:-

    [KeyBoardManager installKeyboardManager];

    This will handle Keyboard and textfield in your app.

  • Hemant Shinde

    Super cool !