How can I navigate through all my text fields with the "Next" Button on the iPhone Keyboard?
The last text field should close the Keyboard.
I've setup the IB the Buttons (Next / Done) but now I'm stuck.
I implemented the textFieldShouldReturn action but now the Next and Done Buttons close the Keyboard.
In Cocoa for Mac OS X, you have the next responder chain, where you can ask the text field what control should have focus next. This is what makes tabbing between text fields work. But since iOS devices do not have a keyboard, only touch, this concept has not survived the transition to Cocoa Touch.
This can be easily done anyway, with two assumptions:
All "tabbable" UITextFields are on the same parent view.
Their "tab-order" is defined by the tag property.
Assuming this you can override textFieldShouldReturn: as this:
-(BOOL)textFieldShouldReturn:(UITextField*)textField
{
NSInteger nextTag = textField.tag + 1;
// Try to find next responder
UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
if (nextResponder) {
// Found next responder, so set it.
[nextResponder becomeFirstResponder];
} else {
// Not found, so remove keyboard.
[textField resignFirstResponder];
}
return NO; // We do not want UITextField to insert line-breaks.
}
Add some more code, and the assumptions can be ignored as well.
Swift 4.0
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let nextTag = textField.tag + 1
// Try to find next responder
let nextResponder = textField.superview?.viewWithTag(nextTag) as UIResponder!
if nextResponder != nil {
// Found next responder, so set it
nextResponder?.becomeFirstResponder()
} else {
// Not found, so remove keyboard
textField.resignFirstResponder()
}
return false
}
If the superview of the text field will be a UITableViewCell then next responder will be
let nextResponder = textField.superview?.superview?.superview?.viewWithTag(nextTag) as UIResponder!
There is a much more elegant solution which blew me away the first time I saw it. Benefits:
Closer to OSX textfield implementation where a textfield knows where the focus should go next
Does not rely on setting or using tags -- which are, IMO fragile for this use case
Can be extended to work with both UITextField and UITextView controls -- or any keyboard entry UI control
Doesn't clutter your view controller with boilerplate UITextField delegate code
Integrates nicely with IB and can be configured through the familiar option-drag-drop to connect outlets.
Create a UITextField subclass which has an IBOutlet property called nextField. Here's the header:
#interface SOTextField : UITextField
#property (weak, nonatomic) IBOutlet UITextField *nextField;
#end
And here's the implementation:
#implementation SOTextField
#end
In your view controller, you'll create the -textFieldShouldReturn: delegate method:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ([textField isKindOfClass:[SOTextField class]]) {
UITextField *nextField = [(SOTextField *)textField nextField];
if (nextField) {
dispatch_async(dispatch_get_current_queue(), ^{
[nextField becomeFirstResponder];
});
}
else {
[textField resignFirstResponder];
}
}
return YES;
}
In IB, change your UITextFields to use the SOTextField class. Next, also in IB, set the delegate for each of the 'SOTextFields'to 'File's Owner' (which is right where you put the code for the delegate method - textFieldShouldReturn). The beauty of this design is that now you can simply right-click on any textField and assign the nextField outlet to the next SOTextField object you want to be the next responder.
Moreover, you can do cool things like loop the textFields so that after the last one loses focus, the first one will receive focus again.
This can easily be extended to automatically assign the returnKeyType of the SOTextField to a UIReturnKeyNext if there is a nextField assigned -- one less thing manually configure.
Here's one without delegation:
tf1.addTarget(tf2, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
tf2.addTarget(tf3, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
ObjC:
[tf1 addTarget:tf2 action:#selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
[tf2 addTarget:tf3 action:#selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
Works using the (mostly unknown) UIControlEventEditingDidEndOnExit UITextField action.
You can also easily hook this up in the storyboard, so no delegation or code is required.
Edit: actually I cannot figure out how to hook this up in storyboard. becomeFirstResponder does not seem to be a offered action for this control-event, which is a pity. Still, you can hook all your textfields up to a single action in your ViewController which then determines which textField to becomeFirstResponder based on the sender (though then it is not as elegant as the above programmatic solution so IMO do it with the above code in viewDidLoad).
Here is my solution for this problem.
To solve this (and because I hate relying on tags to do stuff) I decided to add a custom property to the UITextField object. In other words I created a category on UITextField like this :
UITextField+Extended.h
#interface UITextField (Extended)
#property(retain, nonatomic)UITextField* nextTextField;
#end
UITextField+Extended.m
#import "UITextField+Extended.h"
#import <objc/runtime.h>
static char defaultHashKey;
#implementation UITextField (Extended)
- (UITextField*) nextTextField {
return objc_getAssociatedObject(self, &defaultHashKey);
}
- (void) setNextTextField:(UITextField *)nextTextField{
objc_setAssociatedObject(self, &defaultHashKey, nextTextField, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
Now, here is how I use it :
UITextField *textField1 = ...init your textfield
UITextField *textField2 = ...init your textfield
UITextField *textField3 = ...init your textfield
textField1.nextTextField = textField2;
textField2.nextTextField = textField3;
textField3.nextTextField = nil;
And implement the textFieldShouldReturn method :
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
UITextField *next = theTextField.nextTextField;
if (next) {
[next becomeFirstResponder];
} else {
[theTextField resignFirstResponder];
}
return NO;
}
I now have kind of a linked list of UITextField, each one knowing who's next in the line.
Hope it'll help.
A swift extension that applies mxcl's answer to make this particularly easy (adapted to swift 2.3 by Traveler):
extension UITextField {
class func connectFields(fields:[UITextField]) -> Void {
guard let last = fields.last else {
return
}
for i in 0 ..< fields.count - 1 {
fields[i].returnKeyType = .Next
fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
}
last.returnKeyType = .Done
last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), forControlEvents: .EditingDidEndOnExit)
}
}
It's easy to use:
UITextField.connectFields([field1, field2, field3])
The extension will set the return button to "Next" for all but the last field and to "Done" for the last field, and shift focus / dismiss the keyboard when these are tapped.
Swift < 2.3
extension UITextField {
class func connectFields(fields:[UITextField]) -> Void {
guard let last = fields.last else {
return
}
for var i = 0; i < fields.count - 1; i += 1 {
fields[i].returnKeyType = .Next
fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
}
last.returnKeyType = .Done
last.addTarget(last, action: "resignFirstResponder", forControlEvents: .EditingDidEndOnExit)
}
}
SWIFT 3:
use like this -
UITextField.connectFields(fields: [field1, field2])
Extension:
extension UITextField {
class func connectFields(fields:[UITextField]) -> Void {
guard let last = fields.last else {
return
}
for i in 0 ..< fields.count - 1 {
fields[i].returnKeyType = .next
fields[i].addTarget(fields[i+1], action: #selector(UIResponder.becomeFirstResponder), for: .editingDidEndOnExit)
}
last.returnKeyType = .go
last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), for: .editingDidEndOnExit)
}
}
A more consistent and robust way is to use NextResponderTextField
You can configure it totally from interface builder with no need for setting the delegate or using view.tag.
All you need to do is
Set the class type of your UITextField to be NextResponderTextField
Then set the outlet of the nextResponderField to point to the next responder it can be anything UITextField or any UIResponder subclass. It can be also a UIButton and the library is smart enough to trigger the TouchUpInside event of the button only if it's enabled.
Here is the library in action:
I like the OO solutions that have already been suggested by Anth0 and Answerbot. However, I was working on a quick and small POC, so I didn't want to clutter things with subclasses and categories.
Another simple solution is to create an NSArray of fields and lookup the next field when you press next. Not an OO solution, but quick, simple, and easy to implement. Also, you can see and modify the ordering at a glance.
Here's my code (built upon other answers in this thread):
#property (nonatomic) NSArray *fieldArray;
- (void)viewDidLoad {
[super viewDidLoad];
fieldArray = [NSArray arrayWithObjects: firstField, secondField, thirdField, nil];
}
- (BOOL) textFieldShouldReturn:(UITextField *) textField {
BOOL didResign = [textField resignFirstResponder];
if (!didResign) return NO;
NSUInteger index = [self.fieldArray indexOfObject:textField];
if (index == NSNotFound || index + 1 == fieldArray.count) return NO;
id nextField = [fieldArray objectAtIndex:index + 1];
activeField = nextField;
[nextField becomeFirstResponder];
return NO;
}
I always return NO because I don't want a line break inserted. Just thought I'd point that out since when I returned YES it would automatically exit the subsequent fields or insert a line break in my TextView. It took me a bit of time to figure that out.
activeField keeps track of the active field in case scrolling is necessary to unobscure the field from the keyboard. If you have similar code, make sure you assign the activeField before changing the first responder. Changing first responder is immediate and will fire the KeyboardWasShown event immediately.
Here is an implementation of tabbing using a category on UIControl. This solution has all of the advantages of the methods from Michael and Anth0, but works for all UIControls, not just UITextFields. It also works seamlessly with Interface Builder and storyboards.
Source and sample app: GitHub repository for UIControlsWithTabbing
Usage:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField transferFirstResponderToNextControl];
return NO;
}
Header:
//
// UIControl+NextControl.h
// UIControlsWithTabbing
//
#import <UIKit/UIKit.h>
#interface UIControl (NextControl)
#property (nonatomic, weak) IBOutlet UIControl *nextControl;
- (BOOL)transferFirstResponderToNextControl;
#end
Implementation:
#import "UIControl+NextControl.h"
#import <objc/runtime.h>
static char defaultHashKey;
#implementation UIControl (NextControl)
- (UIControl *)nextControl
{
return objc_getAssociatedObject(self, &defaultHashKey);
}
- (void)setNextControl:(UIControl *)nextControl
{
objc_setAssociatedObject(self, &defaultHashKey, nextControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)transferFirstResponderToNextControl
{
if (self.nextControl)
{
[self.nextControl becomeFirstResponder];
return YES;
}
[self resignFirstResponder];
return NO;
}
#end
I have tried many codes and finally, this worked for me in Swift 3.0 Latest [March 2017]
The ViewController class should be inherited the UITextFieldDelegate for making this code working.
class ViewController: UIViewController,UITextFieldDelegate
Add the Text field with the Proper Tag number and this tag number is used to take the control to appropriate text field based on incremental tag number assigned to it.
override func viewDidLoad() {
userNameTextField.delegate = self
userNameTextField.tag = 0
userNameTextField.returnKeyType = UIReturnKeyType.next
passwordTextField.delegate = self
passwordTextField.tag = 1
passwordTextField.returnKeyType = UIReturnKeyType.go
}
In the above code, the returnKeyType = UIReturnKeyType.next where will make the Key pad return key to display as Next you also have other options as Join/Go etc, based on your application change the values.
This textFieldShouldReturn is a method of UITextFieldDelegate controlled and here we have next field selection based on the Tag value incrementation
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
return true;
}
return false
}
After you exit from one text field, you call [otherTextField becomeFirstResponder] and the next field gets focus.
This can actually be a tricky problem to deal with since often you'll also want to scroll the screen or otherwise adjust the position of the text field so it's easy to see when editing. Just make sure to do a lot of testing with coming into and out of the text fields in different ways and also leaving early (always give the user an option to dismiss the keyboard instead of going to the next field, usually with "Done" in the nav bar)
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[[self.view viewWithTag:textField.tag+1] becomeFirstResponder];
return YES;
}
I am surprised by how many answers here fail to understand one simple concept: navigating through controls in your app is not something the views themselves should do. It's the controller's job to decide which control to make the next first responder.
Also most answers only applied to navigating forward, but users may also want to go backwards.
So here's what I've come up with. Your form should be managed by a view controller, and view controllers are part of the responder chain. So you're perfectly free to implement the following methods:
#pragma mark - Key Commands
- (NSArray *)keyCommands
{
static NSArray *commands;
static dispatch_once_t once;
dispatch_once(&once, ^{
UIKeyCommand *const forward = [UIKeyCommand keyCommandWithInput:#"\t" modifierFlags:0 action:#selector(tabForward:)];
UIKeyCommand *const backward = [UIKeyCommand keyCommandWithInput:#"\t" modifierFlags:UIKeyModifierShift action:#selector(tabBackward:)];
commands = #[forward, backward];
});
return commands;
}
- (void)tabForward:(UIKeyCommand *)command
{
NSArray *const controls = self.controls;
UIResponder *firstResponder = nil;
for (UIResponder *const responder in controls) {
if (firstResponder != nil && responder.canBecomeFirstResponder) {
[responder becomeFirstResponder]; return;
}
else if (responder.isFirstResponder) {
firstResponder = responder;
}
}
[controls.firstObject becomeFirstResponder];
}
- (void)tabBackward:(UIKeyCommand *)command
{
NSArray *const controls = self.controls;
UIResponder *firstResponder = nil;
for (UIResponder *const responder in controls.reverseObjectEnumerator) {
if (firstResponder != nil && responder.canBecomeFirstResponder) {
[responder becomeFirstResponder]; return;
}
else if (responder.isFirstResponder) {
firstResponder = responder;
}
}
[controls.lastObject becomeFirstResponder];
}
Additional logic for scrolling offscreen responders visible beforehand may apply.
Another advantage of this approach is that you don't need to subclass all kinds of controls you may want to display (like UITextFields) but can instead manage the logic at controller level, where, let's be honest, is the right place to do so.
A very easy method for dismissing the keyboard when the 'Done' button is pressed is:
Create a new IBAction in the header
- (IBAction)textFieldDoneEditing:(id)sender;
In the implementation file (.m file) add the following method:
- (IBAction)textFieldDoneEditing:(id)sender
{
[sender resignFirstResponder];
}
Then, when you come to link the IBAction to the textfield - link to the 'Did End On Exit' event.
First set keyboard return key in xib, otherwise you can write code in viewdidload:
passWord.returnKeyType = UIReturnKeyNext;
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
if(textField == eMail) {
[textField resignFirstResponder];
[userName becomeFirstResponder];
}
if (textField==userName) {
[textField resignFirstResponder];
[passWord becomeFirstResponder];
}
if (textField==passWord) {
[textField resignFirstResponder];
[country becomeFirstResponder];
}
if (textField==country) {
[textField resignFirstResponder];
}
return YES;
}
If someone wants like this. I think this is the closest to the requirements asked for in question
Here is how I have implemented this one
Add accessory view for each text field for which you want the setup, using
func setAccessoryViewFor(textField : UITextField) {
let toolBar = UIToolbar()
toolBar.barStyle = .default
toolBar.isTranslucent = true
toolBar.sizeToFit()
// Adds the buttons
// Add previousButton
let prevButton = UIBarButtonItem(title: "<", style: .plain, target: self, action: #selector(previousPressed(sender:)))
prevButton.tag = textField.tag
if getPreviousResponderFor(tag: textField.tag) == nil {
prevButton.isEnabled = false
}
// Add nextButton
let nextButton = UIBarButtonItem(title: ">", style: .plain, target: self, action: #selector(nextPressed(sender:)))
nextButton.tag = textField.tag
if getNextResponderFor(tag: textField.tag) == nil {
nextButton.title = "Done"
}
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
toolBar.setItems([prevButton,spaceButton,nextButton], animated: false)
toolBar.isUserInteractionEnabled = true
textField.inputAccessoryView = toolBar
}
Use following functions to handle taps
func nextPressed(sender : UIBarButtonItem) {
if let nextResponder = getNextResponderFor(tag: sender.tag) {
nextResponder.becomeFirstResponder()
} else {
self.view.endEditing(true)
}
}
func previousPressed(sender : UIBarButtonItem) {
if let previousResponder = getPreviousResponderFor(tag : sender.tag) {
previousResponder.becomeFirstResponder()
}
}
func getNextResponderFor(tag : Int) -> UITextField? {
return self.view.viewWithTag(tag + 1) as? UITextField
}
func getPreviousResponderFor(tag : Int) -> UITextField? {
return self.view.viewWithTag(tag - 1) as? UITextField
}
You will need to give the textFields tags in sequence in which you want the next/prev button to respond.
Solution in Swift 3.1, After connecting your textfields IBOutlets set your textfields delegate in viewDidLoad, And then navigate your action in textFieldShouldReturn
class YourViewController: UIViewController,UITextFieldDelegate {
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var phoneTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.passwordTextField.delegate = self
self.phoneTextField.delegate = self
// Set your return type
self.phoneTextField.returnKeyType = .next
self.passwordTextField.returnKeyType = .done
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool{
if textField == self.phoneTextField {
self.passwordTextField.becomeFirstResponder()
}else if textField == self.passwordTextField{
// Call login api
self.login()
}
return true
}
}
I have added to PeyloW's answer in case you're looking to implement a previous/next button functionality:
- (IBAction)moveThroughTextFields:(UIBarButtonItem *)sender
{
NSInteger nextTag;
UITextView *currentTextField = [self.view findFirstResponderAndReturn];
if (currentTextField != nil) {
// I assigned tags to the buttons. 0 represent prev & 1 represents next
if (sender.tag == 0) {
nextTag = currentTextField.tag - 1;
} else if (sender.tag == 1) {
nextTag = currentTextField.tag + 1;
}
}
// Try to find next responder
UIResponder* nextResponder = [self.view viewWithTag:nextTag];
if (nextResponder) {
// Found next responder, so set it.
// I added the resign here in case there's different keyboards in place.
[currentTextField resignFirstResponder];
[nextResponder becomeFirstResponder];
} else {
// Not found, so remove keyboard.
[currentTextField resignFirstResponder];
}
}
Where you subclass the UIView like this:
#implementation UIView (FindAndReturnFirstResponder)
- (UITextView *)findFirstResponderAndReturn
{
for (UITextView *subView in self.subviews) {
if (subView.isFirstResponder){
return subView;
}
}
return nil;
}
#end
Hi to everyone please see this one
- (void)nextPrevious:(id)sender
{
UIView *responder = [self.view findFirstResponder];
if (nil == responder || ![responder isKindOfClass:[GroupTextField class]]) {
return;
}
switch([(UISegmentedControl *)sender selectedSegmentIndex]) {
case 0:
// previous
if (nil != ((GroupTextField *)responder).previousControl) {
[((GroupTextField *)responder).previousControl becomeFirstResponder];
DebugLog(#"currentControl: %i previousControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).previousControl.tag);
}
break;
case 1:
// next
if (nil != ((GroupTextField *)responder).nextControl) {
[((GroupTextField *)responder).nextControl becomeFirstResponder];
DebugLog(#"currentControl: %i nextControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).nextControl.tag);
}
break;
}
}
I tried to solve this problem using a more sophisticated approach based on assigning each cell (or UITextField) in a UITableView a unique tag value that can be later retrieved:
activate-next-uitextfield-in-uitableview-ios
I hope this helps!
I've just created new Pod when dealing with this stuff GNTextFieldsCollectionManager. It automatically handles next/last textField problem and is very easy to use:
[[GNTextFieldsCollectionManager alloc] initWithView:self.view];
Grabs all textfields sorted by appearing in view hierarchy (or by tags), or you can specify your own array of textFields.
A safer and more direct way, assuming:
the text field delegates are set to your view controller
all of the text fields are subviews of the same view
the text fields have tags in the order you want to progress (e.g., textField2.tag = 2, textField3.tag = 3, etc.)
moving to the next text field will happen when you tap the return button on the keyboard (you can change this to next, done, etc.)
you want the keyboard to dismiss after the last text field
Swift 4.1:
extension ViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let nextTag = textField.tag + 1
guard let nextTextField = textField.superview?.viewWithTag(nextTag) else {
textField.resignFirstResponder()
return false
}
nextTextField.becomeFirstResponder()
return false
}
}
I rather prefer to:
#interface MyViewController : UIViewController
#property (nonatomic, retain) IBOutletCollection(UIView) NSArray *inputFields;
#end
In the NIB file I hook the textFields in the desired order into this inputFields array. After that I do a simple test for the index of the UITextField that reports that the user tapped return:
// for UITextField
-(BOOL)textFieldShouldReturn:(UITextField*)textField {
NSUInteger index = [_inputFields indexOfObject:textField];
index++;
if (index < _inputFields.count) {
UIView *v = [_inputFields objectAtIndex:index];
[v becomeFirstResponder];
}
return NO;
}
// for UITextView
-(BOOL)textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
if ([#"\n" isEqualToString:text]) {
NSUInteger index = [_inputFields indexOfObject:textView];
index++;
if (index < _inputFields.count) {
UIView *v = [_inputFields objectAtIndex:index];
[v becomeFirstResponder];
} else {
[self.view endEditing:YES];
}
return NO;
}
return YES;
}
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
txt_Input = [[ UITextField alloc] initWithFrame:CGRectMake(0, 10, 150, 30)];
txt_Input.tag = indexPath.row+1;
[self.array_Textfields addObject:txt_Input]; // Initialize mutable array in ViewDidLoad
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
int tag = ( int) textField.tag ;
UITextField * txt = [ self.array_Textfields objectAtIndex:tag ] ;
[ txt becomeFirstResponder] ;
return YES ;
}
I had about 10+ UITextField in my story board and the way I enabled next functionality was by creating an array of UITextField and making the next UITextField the firstResponder. Here's the implementation file:
#import "RegistrationTableViewController.h"
#interface RegistrationTableViewController ()
#property (weak, nonatomic) IBOutlet UITextField *fullNameTextField;
#property (weak, nonatomic) IBOutlet UITextField *addressTextField;
#property (weak, nonatomic) IBOutlet UITextField *address2TextField;
#property (weak, nonatomic) IBOutlet UITextField *cityTextField;
#property (weak, nonatomic) IBOutlet UITextField *zipCodeTextField;
#property (weak, nonatomic) IBOutlet UITextField *urlTextField;
#property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
#property (weak, nonatomic) IBOutlet UITextField *emailTextField;
#property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
#property (weak, nonatomic) IBOutlet UITextField *confirmPWTextField;
#end
NSArray *uiTextFieldArray;
#implementation RegistrationTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"view did load");
uiTextFieldArray = #[self.fullNameTextField,self.addressTextField,self.address2TextField,self.cityTextField,self.zipCodeTextField,self.urlTextField,self.usernameTextField,self.emailTextField,self.passwordTextField,self.confirmPWTextField];
for(UITextField *myField in uiTextFieldArray){
myField.delegate = self;
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
long index = [uiTextFieldArray indexOfObject:textField];
NSLog(#"%ld",index);
if(index < (uiTextFieldArray.count - 1)){
[uiTextFieldArray[++index] becomeFirstResponder];
}else{
[uiTextFieldArray[index] resignFirstResponder];
}
return YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This worked for me in Xamarin.iOS / Monotouch.
Change the keyboard button to Next, pass the control to the next UITextField and hide the keyboard after the last UITextField.
private void SetShouldReturnDelegates(IEnumerable<UIView> subViewsToScout )
{
foreach (var item in subViewsToScout.Where(item => item.GetType() == typeof (UITextField)))
{
(item as UITextField).ReturnKeyType = UIReturnKeyType.Next;
(item as UITextField).ShouldReturn += (textField) =>
{
nint nextTag = textField.Tag + 1;
var nextResponder = textField.Superview.ViewWithTag(nextTag);
if (null != nextResponder)
nextResponder.BecomeFirstResponder();
else
textField.Superview.EndEditing(true);
//You could also use textField.ResignFirstResponder();
return false; // We do not want UITextField to insert line-breaks.
};
}
}
Inside the ViewDidLoad you'll have:
If your TextFields haven't a Tag set it now:
txtField1.Tag = 0;
txtField2.Tag = 1;
txtField3.Tag = 2;
//...
and just the call
SetShouldReturnDelegates(yourViewWithTxtFields.Subviews.ToList());
//If you are not sure of which view contains your fields you can also call it in a safer way:
SetShouldReturnDelegates(txtField1.Superview.Subviews.ToList());
//You can also reuse the same method with different containerViews in case your UITextField are under different views.
This is a simple solution in swift, with no tag using, no storyboard tricks...
Just use this extension :
extension UITextField{
func nextTextFieldField() -> UITextField?{
//field to return
var returnField : UITextField?
if self.superview != nil{
//for each view in superview
for (_, view) in self.superview!.subviews.enumerate(){
//if subview is a text's field
if view.isKindOfClass(UITextField){
//cast curent view as text field
let currentTextField = view as! UITextField
//if text field is after the current one
if currentTextField.frame.origin.y > self.frame.origin.y{
//if there is no text field to return already
if returnField == nil {
//set as default return
returnField = currentTextField
}
//else if this this less far than the other
else if currentTextField.frame.origin.y < returnField!.frame.origin.y{
//this is the field to return
returnField = currentTextField
}
}
}
}
}
//end of the mdethod
return returnField
}
}
And call it like this (for example) with your textfield delegate:
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
textField.nextTextFieldField()?.becomeFirstResponder()
return true
}
Here is a Swift 3 version of Anth0's answer. I'm posting it here to help any swift developers in wanting to take advantage of his great answer! I took the liberty of adding a return key type of "Next" when you set the associated object.
extension UITextField {
#nonobjc static var NextHashKey: UniChar = 0
var nextTextField: UITextField? {
get {
return objc_getAssociatedObject(self,
&UITextField.NextHashKey) as? UITextField
}
set(next) {
self.returnKeyType = UIReturnKeyType.next
objc_setAssociatedObject(self,
&UITextField.NextHashKey,next,.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
Here is another extension that shows a possibility of using the above code to cycle through a list of UITextFields.
extension UIViewController: UITextFieldDelegate {
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
guard let next = textField.nextTextField else {
textField.resignFirstResponder()
return true
}
next.becomeFirstResponder()
return false
}
}
And then in your ViewController or wherever, you can setup your textfields like so...
#IBOutlet fileprivate weak var textfield1: UITextField!
#IBOutlet fileprivate weak var textfield2: UITextField!
#IBOutlet fileprivate weak var textfield3: UITextField!
...
[textfield1, textfield2, textfield3].forEach{ $0?.delegate = self }
textfield1.nextTextField = textfield2
textfield2.nextTextField = textfield3
// We don't assign a nextTextField to textfield3 because we want
// textfield3 to be the last one and resignFirstResponder when
// the return button on the soft keyboard is tapped.
in textFieldShouldReturn you should check that the textfield you are currently on is not the last one when they click next and if its n ot dont dismiss the keyboard..
This is an old post, but has a high page rank so I'll chime in with my solution.
I had a similar issue and ended up creating a subclass of UIToolbar to manage the next/previous/done functionality in a dynamic tableView with sections: https://github.com/jday001/DataEntryToolbar
You set the toolbar as inputAccessoryView of your text fields and add them to its dictionary. This allows you to cycle through them forwards and backwards, even with dynamic content. There are delegate methods if you want to trigger your own functionality when textField navigation happens, but you don't have to deal with managing any tags or first responder status.
There are code snippets & an example app at the GitHub link to help with the implementation details. You will need your own data model to keep track of the values inside the fields.
Without usings tags and without adding a property for nextField/nextTextField, you can try this to emulate TAB, where "testInput" is your current active field:
if ([textInput isFirstResponder])
[textInput.superview.subviews enumerateObjectsAtIndexes:
[NSIndexSet indexSetWithIndexesInRange:
NSMakeRange([textInput.superview.subviews indexOfObject:textInput]+1,
[textInput.superview.subviews count]-[textInput.superview.subviews indexOfObject:textInput]-1)]
options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
*stop = !obj.hidden && [obj becomeFirstResponder];
}];
if ([textInput isFirstResponder])
[textInput.superview.subviews enumerateObjectsAtIndexes:
[NSIndexSet indexSetWithIndexesInRange:
NSMakeRange(0,
[textInput.superview.subviews indexOfObject:textInput])]
options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
*stop = !obj.hidden && [obj becomeFirstResponder];
}];
Related
I have looked everywhere for this answer but I haven't gotten a simple easy to follow answer to this question. I have 8 text fields that I need to fill out before I click and submit before moving onto the next page. I have hooked up each of the textfields to view controller.h file but I don't know how to disable the submit button easily step by step. Thank you so much for the help in advance.
I have tried this from a previous post but I could not get it to work..
Make an Outlet for every UITextField and create an IBAction in your .h:
IBOutlet UITextField *textField1;
IBOutlet UITextField *textField2;
IBOutlet UITextField *textField3;
IBOutlet UIButton *button
- (IBAction)editingChanged;
Connect all the outlets and connect the IBAction to every textfield with editingChanged:
- (IBAction)editingChanged {
if ([textfield1.text length] != 0 && [textfield2.text length] != 0 && [textfield3.text length] != 0) {
[button setEnabled:YES];
}
else {
[button setEnabled:NO];
}
}
Note that you can also use [textfield.text isEqualToString:#""] and put a ! in front of it (!means 'not' in objective-c) to recognize the empty textField, and say 'if the textField is empty do...'
- (void)viewDidLoad {
[super viewDidLoad];
[button setEnabled:NO];
}
try this,
1) You need to add textfiled delegate function to all your textfiled.
.h
#interface ViewController : UIViewController <UITextFieldDelegate>
.m
- (void)viewDidLoad
{
[super viewDidLoad];
//set submit button disable
submitbtn.enable=NO
textfiled1.delegate = self;
textfiled2.delegate = self;
textfiled3.delegate = self;
textfiled4.delegate = self;
textfiled5.delegate = self;
textfiled6.delegate = self;
textfiled7.delegate = self;
textfiled8.delegate = self;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
//check your all texfield length if not equal to zero in below if(condition)
if(alltextfiled_length != 0)
{
submitbtn.enable=YES
}
else
{
submitbtn.enable=NO
}
}
I suggest you read the documentation on connecting outlets.
To handle changes in the text fields your view controller class could conform to the UITextFieldDelegate protocol, assign your view controller as the delegate of each text field, and implement - (BOOL)textFieldShouldReturn:(UITextField *)textField which will be called when tapping the Return button on each text field's keyboard.
I have a table with UITextFields, and I want to make it so that when a textfield is selected, the current info is cleared (to allow new input), but if the user decides (after selecting) that they don't want to change it, I want them to be able to click elsewhere and the data from before reappears in the textfield.
Is there an easy way to do this?
A good way to do this that's nice and user friendly is to use the placeholder property. Set up your viewController as the textfield's delegate (as described by Andeh) then add the following code:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
textField.placeholder = textField.text;
textField.text = #"";
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
if (textField.text.length == 0) {
textField.text = textField.placeholder;
}
textField.placeholder = #"";
}
And you're done. If you have multiple UITextFields on the page and you don't want this behaviour for all of them you can add a check to the methods above.
In the textFieldDidBeginEditing delegate method, save the current value to a persisting variable before clearing the UITextField. Then in the didFinishEditing delegate method, if the new length of the user input is 0 set the text back to the stored value!
UITextField Delegate docs for reference.
First I think you have two sets of behaviors here.
The text field must clear the value when you begin editing. This exists: -clearsOnBeginEditing.
The text field must restore the previous text if text is empty. Subclassing seems the better solution.
Here is a possible sample class:
// MyRestoringTextField.h
#interface MyRestoringTextField : UITextField
#end
// MyTextField.m
#interface MyRestoringTextField ()
#property (strong, nonatomic) NSString *previousText;
#end
#implementation MyRestoringTextField
- (BOOL)becomeFirstResponder
{
BOOL result = [super becomeFirstResponder];
self.previousText = self.text;
return result;
}
- (BOOL)resignFirstResponder
{
BOOL result = [super resignFirstResponder];
if (self.text.length == 0)
self.text = self.previousText;
return result;
}
#end
Hope that helps.
To clear and then restore a textField if you fail to make an entry, use the following delegates as such:
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[[NSUserDefaults standardUserDefaults] setObject:textField.text forKey:kTextFieldIdentifier];
textField.text = #"";
}
-(BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
if ([textField.text isEqualToString:#""])
textField.text = [[NSUserDefaults standardUserDefaults]
stringForKey:kTextFieldIdentifier];
return YES;
}
As of iOS 8.1, textFieldDidBeginEditing is already receiving a cleared text. You should use
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField
to initialized the placeholder field.
I have two UITextFields (e.g. username and password) but I cannot get rid of the keyboard when pressing the return key on the keyboard. How can I do this?
First you need to conform to the UITextFieldDelegate Protocol in your View/ViewController's header file like this:
#interface YourViewController : UIViewController <UITextFieldDelegate>
Then in your .m file you need to implement the following UITextFieldDelegate protocol method:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
[textField resignFirstResponder]; makes sure the keyboard is dismissed.
Make sure you're setting your view/viewcontroller to be the UITextField's delegate after you init the textfield in the .m:
yourTextField = [[UITextField alloc] initWithFrame:yourFrame];
//....
//....
//Setting the textField's properties
//....
//The next line is important!!
yourTextField.delegate = self; //self references the viewcontroller or view your textField is on
Implement the UITextFieldDelegate method like this:
- (BOOL)textFieldShouldReturn:(UITextField *)aTextField
{
[aTextField resignFirstResponder];
return YES;
}
See Managing the Keyboard for a complete discussion on this topic.
Your UITextFields should have a delegate object (UITextFieldDelegate). Use the following code in your delegate to make the keyboard disappear:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
}
Should work so far...
Took me couple trials, had same issue, this worked for me:
Check your spelling at -
(BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
I corrected mine at textField instead of textfield, capitalise "F"... and bingo!! it worked..
When the return key is pressed, call:
[uitextfield resignFirstResponder];
After quite a bit of time hunting down something that makes sense, this is what I put together and it worked like a charm.
.h
//
// ViewController.h
// demoKeyboardScrolling
//
// Created by Chris Cantley on 11/14/13.
// Copyright (c) 2013 Chris Cantley. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITextFieldDelegate>
// Connect your text field to this the below property.
#property (weak, nonatomic) IBOutlet UITextField *theTextField;
#end
.m
//
// ViewController.m
// demoKeyboardScrolling
//
// Created by Chris Cantley on 11/14/13.
// Copyright (c) 2013 Chris Cantley. All rights reserved.
//
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// _theTextField is the name of the parameter designated in the .h file.
_theTextField.returnKeyType = UIReturnKeyDone;
[_theTextField setDelegate:self];
}
// This part is more dynamic as it closes the keyboard regardless of what text field
// is being used when pressing return.
// You might want to control every single text field separately but that isn't
// what this code do.
-(void)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
}
#end
Hope this helps!
Set the Delegate of the UITextField to your ViewController, add a referencing outlet between the File's Owner and the UITextField, then implement this method:
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == yourTextField)
{
[textField resignFirstResponder];
}
return NO;
}
Add this instead of the pre-defined class
class ViewController: UIViewController, UITextFieldDelegate {
To remove keyboard when clicked outside the keyboard
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
and to remove keyboard when pressed enter
add this line in viewDidLoad()
inputField is the name of the textField used.
self.inputField.delegate = self
and add this function
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
Swift 2 :
this is what is did to do every thing !
close keyboard with Done button or Touch outSide ,Next for go to next input.
First Change TextFiled Return Key To Next in StoryBoard.
override func viewDidLoad() {
txtBillIdentifier.delegate = self
txtBillIdentifier.tag = 1
txtPayIdentifier.delegate = self
txtPayIdentifier.tag = 2
let tap = UITapGestureRecognizer(target: self, action: "onTouchGesture")
self.view.addGestureRecognizer(tap)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
if(textField.returnKeyType == UIReturnKeyType.Default) {
if let next = textField.superview?.viewWithTag(textField.tag+1) as? UITextField {
next.becomeFirstResponder()
return false
}
}
textField.resignFirstResponder()
return false
}
func onTouchGesture(){
self.view.endEditing(true)
}
in swift you should delegate UITextfieldDelegate, its important don't forget it, in the viewController, like:
class MyViewController: UITextfieldDelegate{
mytextfield.delegate = self
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
}
}
You can add an IBAction to the uiTextField(the releation event is "Did End On Exit"),and the IBAction may named hideKeyboard,
-(IBAction)hideKeyboard:(id)sender
{
[uitextfield resignFirstResponder];
}
also,you can apply it to the other textFields or buttons,for example,you may add a hidden button to the view,when you click it to hide the keyboard.
You can try this UITextfield subclass which you can set a condition for the text to dynamically change the UIReturnKey:
https://github.com/codeinteractiveapps/OBReturnKeyTextField
If you want to disappear keyboard when writing on alert box textfileds
[[alertController.textFields objectAtIndex:1] resignFirstResponder];
I am working on Text to speech application in iPhone,
in which have a text field that takes input, i want user to select some portion of text from text field and my application will convert that selected text into speech.
my problem is how would i get the text that user has selected from text field?
-[UITextField selectedText]
Although UITextField doesn't have a selectedText method, it conforms to the UITextInput protocol. So, you can use the required properties & methods of the UITextInput protocol to determine the selectedText of a UITextField *textField (or any object that conforms to the UITextInput protocol, such as a UITextView).
NSString *selectedText = [textField textInRange:textField.selectedTextRange];
NSLog(#"selectedText: %#", selectedText);
As an aside, you can also use the required properties & methods of the UITextInput to calculate the selectedRange of a UITextField *textField.
UITextRange *selectedTextRange = textField.selectedTextRange;
NSUInteger location = [textField offsetFromPosition:textField.beginningOfDocument
toPosition:selectedTextRange.start];
NSUInteger length = [textField offsetFromPosition:selectedTextRange.start
toPosition:selectedTextRange.end];
NSRange selectedRange = NSMakeRange(location, length);
NSLog(#"selectedRange: %#", NSStringFromRange(selectedRange));
-[UITextFieldDelegate textFieldDidChangeSelection:]
Although, UITextFieldDelegate doesn't declare a textFieldDidChangeSelection: delegate method like -[UITextViewDelegate textViewDidChangeSelection:], you can still hook into when the selection of a UITextField has changed. To do so, subclass UITextField and use method swizzling to add your own code to the textField.inputDelegate's native implementation of -[UITextInputDelegate selectionDidChange:].
// MyTextField.h
#import <UIKit/UIKit.h>
#interface MyTextField : UITextField
#end
// MyTextField.m
#import <objc/runtime.h>
#import "MyTextField.h"
UIKIT_STATIC_INLINE void mySelectionDidChange(id self, SEL _cmd, id<UITextInput> textInput);
#implementation MyTextField {
BOOL swizzled;
}
#pragma mark - UIResponder
// Swizzle here because self.inputDelegate is set after becomeFirstResponder gets called.
- (BOOL)becomeFirstResponder {
if ([super becomeFirstResponder]) {
[self swizzleSelectionDidChange:YES];
return YES;
} else {
return NO;
}
}
// Unswizzle here because self.inputDelegate may become the inputDelegate for another UITextField.
- (BOOL)resignFirstResponder {
if ([super resignFirstResponder]) {
[self swizzleSelectionDidChange:NO];
return YES;
} else {
return NO;
}
}
#pragma mark - Swizzle -[UITextInput selectionDidChange:]
// Swizzle selectionDidChange: to "do whatever you want" when the text field's selection has changed.
// Only call this method on the main (UI) thread because it may not be thread safe.
- (void)swizzleSelectionDidChange:(BOOL)swizzle {
if (swizzle == swizzled || ![self respondsToSelector:#selector(inputDelegate)]) return; // 4.3
Class inputDelegateClass = object_getClass(self.inputDelegate);
SEL mySelector = #selector(mySelectionDidChange:);
class_addMethod(inputDelegateClass, mySelector, (IMP)mySelectionDidChange, "v#:#");
Method myMethod = class_getInstanceMethod(inputDelegateClass, mySelector);
Method uiKitMethod = class_getInstanceMethod(inputDelegateClass, #selector(selectionDidChange:));
method_exchangeImplementations(uiKitMethod, myMethod);
swizzled = swizzle;
// NSLog(#"swizzled? %i", method_getImplementation(uiKitMethod) == (IMP)venmo_selectionDidChange);
}
#end
UIKIT_STATIC_INLINE void mySelectionDidChange(id self, SEL _cmd, id<UITextInput> textInput) {
// Call the native implementation of selectionDidChange:.
[self performSelector:#selector(mySelectionDidChange:) withObject:textInput];
// "Do whatever you want" with the selectedText below.
NSString *selectedText = [textInput textInRange:textInput.selectedTextRange];
NSLog(#"selectedText: %#", selectedText);
}
I did solve my query as follow :
I implement UITextView's delegate and implement following method
- (void)textViewDidChangeSelection:(UITextView *)textView {
NSRange r = textView.selectedRange;
NSLog(#"Start from : %d",r.location); //starting selection in text selection
NSLog(#"To : %d",r.length); // end position in text selection
NSLog([tv.text substringWithRange:NSMakeRange(r.location, r.length)]); //tv is my text view
}
That's it!
Swift
In Swift, getting the selected text from a UITextField is done like this:
if let textRange = myTextField.selectedTextRange {
let selectedText = myTextField.textInRange(textRange)
}
where textRange is a UITextRange that is used to get the actual selected text.
A similar topic is discussed here: Can I select a specific block of text in a UITextField?
AFAIK there is no event if text is selected. However, you could setup an NSTimer to watch your textfield and check the _selectedRange. If it changes, go fire up your text-to-speech code.
EDIT: I was wrong about the selection. UITextField cannot do what you want to achieve. But if you use UITextView instead, you can implement its UITextViewDelegate and override
- (void)textViewDidChangeSelection:(UITextView *)textView
In there, you can use the selectedRange poperty to get the selection. See this reference for details:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextView_Class/Reference/UITextView.html#//apple_ref/doc/uid/TP40006898-CH3-SW13
UITextField don't have delegate to get the selection range change. We can use KVO to observe selectedTextRange property of UITextfield.
[textField addObserver:self forKeyPath:#"selectedTextRange" options:NSKeyValueObservingOptionNew context:NULL];
Or create UITextField subclass and override setSelectedTextRange method.
I know that I need to tell my UITextField to resign first responder when I want to dismis the keyboard, but I'm not sure how to know when the user has pressed the "Done" key on the keyboard. Is there a notification I can watch for?
I set the delegate of the UITextField to my ViewController class.
In that class I implemented this method as following:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
If you connect the DidEndOnExit event of the text field to an action (IBAction) in InterfaceBuilder, it will be messaged when the user dismisses the keyboard (with the return key) and the sender will be a reference to the UITextField that fired the event.
For example:
-(IBAction)userDoneEnteringText:(id)sender
{
UITextField theField = (UITextField*)sender;
// do whatever you want with this text field
}
Then, in InterfaceBuilder, link the DidEndOnExit event of the text field to this action on your controller (or whatever you're using to link events from the UI). Whenever the user enters text and dismisses the text field, the controller will be sent this message.
You can also create a method in your controller
-(IBAction)editingEnded:(id)sender{
[sender resignFirstResponder];
}
and then in Connection Inspector in IB connect Event "Did End On Exit" to it.
kubi, thanks. Your code worked. Just to be explicit (for newbies like) as you say you have to set the UITextField's delegate to be equal to the ViewController in which the text field resides. You can do this wherever you please. I chose the viewDidLoad method.
- (void)viewDidLoad
{
// sets the textField delegates to equal this viewController ... this allows for the keyboard to disappear after pressing done
daTextField.delegate = self;
}
Here is a trick for getting automatic keyboard dismissal behavior with no code at all. In the nib, edit the First Responder proxy object in the Identity inspector, adding a new first responder action; let's call it dummy:. Now hook the Did End on Exit event of the text field to the dummy: action of the First Responder proxy object. That's it! Since the text field's Did End on Exit event now has an action–target pair, the text field automatically dismisses its keyboard when the user taps Return; and since there is no penalty for not finding a handler for a message sent up the responder chain, the app doesn't crash even though there is no implementation of dummy: anywhere.
In Swift you can write an IBAction in the Controller and set the Did End On Exit event of the text field to that action
#IBAction func returnPressed(sender: UITextField) {
self.view.endEditing(true)
}
Just add
[textField endEditing:YES];
where you want to disable keyboard and display the picker view.
Swift 4.2 and It will work 100%
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.textField.delegate = self
}
// hide key board when the user touches outside keyboard
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
// user presses return key
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
You can also use
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.yourTextField resignFirstResponder];
}
Best one if You have many Uitextfields :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.view endEditing:YES];
}
Here's what I had to do to get it to work, and I think is necessary for anyone with a Number Pad for a keyboard (or any other ones without a done button:
I changed the UIView in the ViewController to a UIControl.
I created a function called
-(IBAction)backgroundIsTapped:(id)sender
This was also defined in the .h file.
After this, I linked to to the 'touch down' bit for the ViewController in Interface Builder.
In the 'background is tapped' function, I put this:
[answerField resignFirstResponder];
Just remember to change 'answerField' to the name of the UITextField you want to remove the keyboard from (obviously make sure your UITextField is defined like below:)
IBOutlet UITextField * <nameoftextfieldhere>;
I know this topic probably died a long time ago... but I'm hoping this will help someone, somewhere!
You will notice that the method "textFieldShouldReturn" provides the text-field object that has hit the DONE key. If you set the TAG you can switch on that text field. Or you can track and compare the object's pointer with some member value stored by its creator.
My approach is like this for a self-study:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSLog(#"%s", __FUNCTION__);
bool fDidResign = [textField resignFirstResponder];
NSLog(#"%s: did %resign the keyboard", __FUNCTION__, fDidResign ? #"" : #"not ");
return fDidResign;
}
Meanwhile, I put the "validation" test that denies the resignation follows. It is only for illustration, so if the user types NO! into the field, it will not dismiss. The behavior was as I wanted, but the sequence of output was not as I expected.
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
NSLog(#"%s", __FUNCTION__);
if( [[textField text] isEqualToString:#"NO!"] ) {
NSLog(#"%#", textField.text);
return NO;
} else {
return YES;
}
}
Following is my NSLog output for this denial followed by the acceptance. You will notice that I am returning the result of the resign, but I expected it to return FALSE to me to report back to the caller?! Other than that, it has the necessary behavior.
13.313 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldReturn:]
13.320 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldEndEditing:]
13.327 StudyKbd[109:207] NO!
13.333 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldReturn:]: did resign the keyboard
59.891 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldReturn:]
59.897 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldEndEditing:]
59.917 StudyKbd[109:207] -[StudyKbdViewController doneEditText]: NO
59.928 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldReturn:]: did resign the keyboard
Here is a quite clean way to end edition with the Return Key or a touch in the background.
In Interface builder, embed your fields in a view of class UIFormView
What does this class :
Automatically attach itself as fields delegate ( Either awaked from nib, or added manually )
Keep a reference on the current edited field
Dismiss the keyboard on return or touch in the background
Here is the code :
Interface
#import <UIKit/UIKit.h>
#interface UIFormView : UIView<UITextFieldDelegate>
-(BOOL)textFieldValueIsValid:(UITextField*)textField;
-(void)endEdit;
#end
Implementation
#import "UIFormView.h"
#implementation UIFormView
{
UITextField* currentEditingTextField;
}
// Automatically register fields
-(void)addSubview:(UIView *)view
{
[super addSubview:view];
if ([view isKindOfClass:[UITextField class]]) {
if ( ![(UITextField*)view delegate] ) [(UITextField*)view setDelegate:self];
}
}
// UITextField Protocol
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
currentEditingTextField = textField;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
currentEditingTextField = NULL;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self endEdit];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if ([self textFieldValueIsValid:textField]) {
[self endEdit];
return YES;
} else {
return NO;
}
}
// Own functions
-(void)endEdit
{
if (currentEditingTextField) {
[currentEditingTextField endEditing:YES];
currentEditingTextField = NULL;
}
}
// Override this in your subclass to handle eventual values that may prevent validation.
-(BOOL)textFieldValueIsValid:(UITextField*)textField
{
return YES;
}
#end
By subclassing the form and overriding the
textFieldValueIsValid: method, you
can avoid end of edition if the value is not correct for the given
field.
If a field has a delegate set in Interface Builder, then the form does not change it. I don't see many reasons to set a different delegate to a particular field, but why not…
There is many ways to improve this form view class - Attach a delegate, do some layout, handle when the keyboards covers a field ( using the currentEditingTextField frame ), automatically start edition for the next field, ...
I personally keep it in my framework, and always subclass it to add features, it is quite often useful "as-is".
I hope it will helps. Cheers all
if you want all editing of in a UIViewController you can use.
[[self view]endEditing:YES];
and if you want dismiss a perticular UITextField keyboard hide then use.
1.add delegate in your viewcontroller.h
<UITextFieldDelegate>
make delegation unable to your textfield .
self.yourTextField.delegate = self;
add this method in to your viewcontroller.
-(BOOL)textFieldShouldEndEditing:(UITextField *)textField{
[textField resignFirstResponder];
return YES;}
Anyone looking for Swift 3
1) Make sure your UITextField's Delegate is wired to your ViewController in the Storyboard
2) Implement UITextFieldDelegate in your ViewController.Swift file (e.g class ViewController: UIViewController, UITextFieldDelegate { )
3) Use the delegate method below
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return false }
Programmatically set the delegate of the UITextField in swift 3
Implement UITextFieldDelegate in your ViewController.Swift file (e.g class ViewController: UIViewController, UITextFieldDelegate { )
lazy var firstNameTF: UITextField = {
let firstname = UITextField()
firstname.placeholder = "FirstName"
firstname.frame = CGRect(x:38, y: 100, width: 244, height: 30)
firstname.textAlignment = .center
firstname.borderStyle = UITextBorderStyle.roundedRect
firstname.keyboardType = UIKeyboardType.default
firstname.delegate = self
return firstname
}()
lazy var lastNameTF: UITextField = {
let lastname = UITextField()
lastname.placeholder = "LastName"
lastname.frame = CGRect(x:38, y: 150, width: 244, height: 30)
lastname.textAlignment = .center
lastname.borderStyle = UITextBorderStyle.roundedRect
lastname.keyboardType = UIKeyboardType.default
lastname.delegate = self
return lastname
}()
lazy var emailIdTF: UITextField = {
let emailid = UITextField()
emailid.placeholder = "EmailId"
emailid.frame = CGRect(x:38, y: 200, width: 244, height: 30)
emailid.textAlignment = .center
emailid.borderStyle = UITextBorderStyle.roundedRect
emailid.keyboardType = UIKeyboardType.default
emailid.delegate = self
return emailid
}()
// Mark:- handling delegate textField..
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == firstNameTF {
lastNameTF.becomeFirstResponder()
}
else if textField == lastNameTF {
emailIdTF.becomeFirstResponder()
}
else {
view.emailIdTF(true)
}
return true
}
Create a function hidekeyboard and link it to the textfield in the .xib file and select DidEndOnExit
-(IBAction)Hidekeyboard
{
textfield_name.resignFirstResponder;
}
If you have created the view using Interface Builder, Use the following
Just create a method,
-(IBAction)dismissKeyboard:(id)sender
{
[sender resignFirstResponder];
}
Just right click the text field in the view , and set the event as Did End on Exit, and wire it to the method "dismissKeyboard".
The best guide for beginners is
"Head First iPhone and iPad Development, 2nd Edition"
try this
- (BOOL) textView: (UITextView*) textView shouldChangeTextInRange: (NSRange) range replacementText: (NSString*) text
{
if ([text isEqualToString:#"\n"]) {
[textView resignFirstResponder];
return NO;
}
return YES;
}
//====================================================
// textFieldShouldReturn:
//====================================================
-(BOOL) textFieldShouldReturn:(UITextField*) textField {
[textField resignFirstResponder];
if(textField.returnKeyType != UIReturnKeyDone){
[[textField.superview viewWithTag: self.nextTextField] becomeFirstResponder];
}
return YES;
}
This is how I dismiss the keyboard in Swift 4.2 and it works for me:
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action:
#selector(dismissKeyboard))
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard (_ sender: UITapGestureRecognizer) {
numberField.resignFirstResponder()
}
Swift 3, iOS 9+
#IBAction private func noteFieldDidEndOnExit(_ sender: UITextField) {}
UPD: It still works fine for me. I think guy that devoted this answer just didn't understand that he needs to bind this action to the UITextField at the storyboard.
textField.returnKeyType = UIReturnKeyDone;