Cómo navegar por los campos de text (Botones Siguiente / Hecho)

¿Cómo puedo navegar por todos los campos de text con el button "Siguiente" en el keyboard del iPhone?

El último campo de text debe cerrar el keyboard.

Configuré los botones IB (Siguiente / Listo) pero ahora estoy atascado.

Implementé la acción textFieldShouldReturn pero ahora los botones Next y Done cierran el keyboard.

En Cocoa para Mac OS X, tiene la siguiente cadena de respuesta, donde puede preguntar al campo de text qué control debe tener el siguiente foco. Esto es lo que hace que la tabulación entre los campos de text funcione. Pero dado que los dispositivos iOS no tienen un keyboard, solo toque, este concepto no ha sobrevivido a la transición a Cocoa Touch.

Esto se puede hacer fácilmente de todos modos, con dos supuestos:

  1. Todos los UITextField "tabbable" están en la misma vista principal.
  2. Su "order de tabulación" está definida por la propiedad de label.

Suponiendo esto, puede anular textFieldShouldReturn: como este:

 -(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. } 

Agregue un poco más de código, y los supuestos pueden ignorarse también.

ACTUALIZACIÓN: – SWIFT 2.0

 func textFieldShouldReturn(textField: UITextField) -> Bool { let nextTage=textField.tag+1; // Try to find next responder let nextResponder=textField.superview?.viewWithTag(nextTage) as UIResponder! if (nextResponder != nil){ // Found next responder, so set it. nextResponder?.becomeFirstResponder() } else { // Not found, so remove keyboard textField.resignFirstResponder() } return false // We do not want UITextField to insert line-breaks. } 

Si la vista de supervisión del campo de text será una UITableViewCell, el próximo respondedor será

 let nextResponder=textField.superview?.superview?.superview?.viewWithTag(nextTage) as UIResponder! 

Hay una solución mucho más elegante que me sorprendió la primera vez que la vi. Beneficios:

  • Más cerca de la implementación del campo de text de OSX donde un campo de text sabe dónde debe ir el enfoque siguiente
  • No confía en establecer o usar tags, que son, IMO frágiles para este caso de uso
  • Se puede extender al trabajo con los controles UITextField y UITextView , o con cualquier control de interfaz de usuario de input de keyboard
  • No desordera su controller de vista con repetición del código de delegado UITextField
  • Se integra muy bien con IB y se puede configurar a través de la opción familiar: drag and drop para conectar tomas de stream.

Cree una subclass UITextField que tenga una propiedad IBOutlet denominada nextField. Aquí está el encabezado:

 @interface SOTextField : UITextField @property (weak, nonatomic) IBOutlet UITextField *nextField; @end 

Y aquí está la implementación:

 @implementation SOTextField @end 

En el controller de vista, creará el método -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; } 

En IB, cambia tus UITextFields para usar la class SOTextField . Luego, también en IB, establezca el delegado para cada uno de los 'SOTextFields'to' File's Owner '(que es justo donde colocó el código para el método de delegado – textFieldShouldReturn). La belleza de este layout es que ahora puede simplemente hacer clic derecho en cualquier campo de text y asignar el siguiente SOTextField al siguiente object de SOTextField que quiera ser el siguiente respondedor.

Asignación nextField en IB

Además, puede hacer cosas geniales como hacer un loop en el textFields para que luego de que el último pierda el foco, el primero recibirá el foco de nuevo.

Esto se puede extender fácilmente para asignar automáticamente el returnKeyType del SOTextField a un UIReturnKeyNext si hay un campo asignado asignado, una cosa less configurada manualmente.

Aquí está mi solución para este problema.

Para resolver esto (y porque no me gusta confiar en las tags para hacer cosas), decidí agregar una propiedad personalizada al object UITextField. En otras palabras, he creado una categoría en UITextField como esta:

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 

Ahora, así es como lo uso:

 UITextField *textField1 = ...init your textfield UITextField *textField2 = ...init your textfield UITextField *textField3 = ...init your textfield textField1.nextTextField = textField2; textField2.nextTextField = textField3; textField3.nextTextField = nil; 

E implementar el método textFieldShouldReturn:

 - (BOOL)textFieldShouldReturn:(UITextField *)theTextField { UITextField *next = theTextField.nextTextField; if (next) { [next becomeFirstResponder]; } else { [theTextField resignFirstResponder]; } return NO; } 

Ahora tengo una especie de list enlazada de UITextField, cada uno sabe quién es el próximo en la línea.

Espero que te sirva de ayuda.

Aquí hay uno sin delegación:

 [tf1 addTarget:tf2 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit]; [tf2 addTarget:tf3 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit]; 

Funciona utilizando la acción (en su mayoría desconocida) UIControlEventEditingDidEndOnExit UITextField .

También puedes enganchar esto fácilmente en el guión gráfico, por lo que no se requiere ninguna delegación ni código.

Editar: en realidad, no puedo entender cómo conectar esto en el guión gráfico. becomeFirstResponder no parece ser una acción ofrecida para este control-evento, lo cual es una lástima. Sin embargo, puede enganchar todos sus campos de text a una sola acción en su ViewController que luego determina qué campo de becomeFirstResponder convertirá en becomeFirstResponder basado en el remitente (aunque entonces no es tan elegante como la solución programática anterior, así que IMO lo hace con el código anterior en viewDidLoad )

Una extensión rápida que aplica la respuesta de mxcl para hacerlo particularmente fácil (adaptado a Swift 2.3 por 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) } } 

Es fácil de usar:

 UITextField.connectFields([field1, field2, field3]) 

La extensión establecerá el button de retorno en "Siguiente" para todos excepto el último campo y en "Listo" para el último campo, y cambiará el enfoque / descartará el keyboard cuando se toca.

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 así –

 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) } } 

Una manera más coherente y robusta es utilizar NextResponderTextField . Puede configurarlo totalmente desde el creador de interfaces sin necesidad de configurar el delegado o usar view.tag .

Todo lo que necesitas hacer es

  1. Establezca el tipo de class de su UITextField como NextResponderTextField introduzca la descripción de la imagen aquí
  2. Luego configure la salida del nextResponderField para apuntar al próximo respondedor, puede ser cualquier cosa UITextField o cualquier subclass UIResponder . También puede ser un button UIB y la biblioteca es lo suficientemente inteligente como para activar el evento TouchUpInside del button solo si está habilitado. introduzca la descripción de la imagen aquíintroduzca la descripción de la imagen aquí

Aquí está la biblioteca en acción:

introduzca la descripción de la imagen aquí

Me gustan las soluciones de OO que ya han sido sugeridas por Anth0 y Answerbot. Sin embargo, estaba trabajando en un POC rápido y pequeño, así que no quería estropear las cosas con subclasss y categorías.

Otra solución simple es crear un NSArray de campos y search el siguiente campo cuando presiona el siguiente. No es una solución de OO, pero rápida, simple y fácil de implementar. Además, puede ver y modificar el order de un vistazo.

Aquí está mi código (construido sobre otras respuestas en este hilo):

 @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; } 
  • Siempre return NO porque no quiero insert un salto de línea. Solo pensé en señalarlo, ya que cuando volví a SÍ saldría automáticamente de los campos siguientes o insertía un salto de línea en mi TextView. Me tomó un poco de time para resolver eso.
  • activeField realiza un seguimiento del campo activo en caso de que sea necesario desplazarse para ignorar el campo desde el keyboard. Si tiene un código similar, asegúrese de asignar el campo activo antes de cambiar el primer respondedor. Cambiar el primer respondedor es inmediato y disparará el evento KeyboardWasShown inmediatamente.

Aquí hay una implementación de tabulación usando una categoría en UIControl. Esta solución tiene todas las ventajas de los methods de Michael y Anth0, pero funciona para todos los UIControls, no solo para UITextField . También funciona a la perfección con Interface Builder y storyboards.

Aplicación de ejemplo y fuente: repository de GitHub para UIControlsWith Tablas

Uso:

 - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField transferFirstResponderToNextControl]; return NO; } 

Asignación de nextControl en Interface Builder

Encabezamiento:

 // // UIControl+NextControl.h // UIControlsWithTabbing // #import <UIKit/UIKit.h> @interface UIControl (NextControl) @property (nonatomic, weak) IBOutlet UIControl *nextControl; - (BOOL)transferFirstResponderToNextControl; @end 

Implementación:

 #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 

Después de salir de un campo de text, llama a [otherTextField becomeFirstResponder] y el siguiente campo se enfoca.

Esto puede ser un problema difícil de tratar, ya que a menudo también querrás desplazarte por la pantalla o, de lo contrario, ajustar la position del campo de text para que sea fácil de ver cuando edites. Solo asegúrate de hacer muchas testings para entrar y salir de los campos de text de diferentes maneras y también salir temprano (siempre le das al usuario la opción de descartar el keyboard en lugar de ir al siguiente campo, generalmente con "Listo" en la barra de navigation)

  -(BOOL)textFieldShouldReturn:(UITextField *)textField { [[self.view viewWithTag:textField.tag+1] becomeFirstResponder]; return YES; } 

Un método muy fácil para descartar el keyboard cuando se presiona el button 'Listo' es:

Crear una nueva IBAction en el encabezado

 - (IBAction)textFieldDoneEditing:(id)sender; 

En el file de implementación (file .m) agregue el siguiente método:

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

Luego, cuando vengas a vincular la IBAction al campo de text – enlace al evento 'Did End on Exit'.

Primero configure la tecla de retorno del keyboard en xib, de lo contrario, puede escribir código en 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; } 

Me sorprende el hecho de cuántas respuestas aquí no logran comprender un concepto simple: navegar por los controles en su aplicación no es algo que deban hacer las vistas mismas. Es el trabajo del controller decidir qué control debe hacer el próximo primer respondedor.

También la mayoría de las respuestas solo se aplican a la navigation hacia adelante, pero los usuarios también pueden querer retroceder.

Así que esto es lo que he inventado. Su formulario debe ser gestionado por un controller de vista, y los controlleres de vista forman parte de la cadena de respuesta. Entonces, usted es perfectamente libre de implementar los siguientes 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]; } 

Se puede aplicar la lógica adicional para desplazarse por los respondedores fuera de pantalla visibles de antemano.

Otra ventaja de este enfoque es que no necesita subclassar todos los types de controles que desee mostrar (como UITextField s), sino que puede administrar la lógica en el nivel del controller, donde, seamos honestos, sea el lugar adecuado para hacer asi que.

He probado muchos códigos y finalmente, esto funcionó para mí en Swift 3.0 Latest [marzo de 2017]

La class ViewController debería henetworkingarse el UITextFieldDelegate para que este código funcione.

 class ViewController: UIViewController,UITextFieldDelegate 

Agregue el campo Texto con el número de Etiqueta adecuada y este número de label se usa para tomar el control en el campo de text apropiado basado en el número de label incremental asignado a él.

 override func viewDidLoad() { userNameTextField.delegate = self userNameTextField.tag = 0 userNameTextField.returnKeyType = UIReturnKeyType.next passwordTextField.delegate = self passwordTextField.tag = 1 passwordTextField.returnKeyType = UIReturnKeyType.go } 

En el código anterior, returnKeyType = UIReturnKeyType.next donde hará que la tecla de retorno del keyboard se muestre como Next , también tendrá otras opciones como Join/Go , etc, según la aplicación que cambie los valores.

Este textFieldShouldReturn es un método de UITextFieldDelegate controlado y aquí tenemos la siguiente selección de campo basada en el incremento del valor de Tag

 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 } 

Agregué la respuesta de PeyloW en caso de que busques implementar una funcionalidad de button anterior / siguiente:

 - (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]; } } 

Donde subclasss la UIView así:

 @implementation UIView (FindAndReturnFirstResponder) - (UITextView *)findFirstResponderAndReturn { for (UITextView *subView in self.subviews) { if (subView.isFirstResponder){ return subView; } } return nil; } @end 

Hola a todos, mira este

 - (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; } } 

Traté de resolver este problema utilizando un enfoque más sofisticado basado en la asignación de cada celda (o UITextField ) en un UITableView un valor de label único que se puede recuperar más tarde: activate-next-uitextfield-in-uitableview-ios

¡Espero que esto ayude!

Esto funcionó para mí en Xamarin.iOS / Monotouch. Cambie el button del keyboard a Siguiente, pase el control al siguiente UITextField y oculte el keyboard después del último 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. }; } } 

Dentro de ViewDidLoad tendrás:

Si su TextFields no tiene una label, ajústelo ahora:

 txtField1.Tag = 0; txtField2.Tag = 1; txtField3.Tag = 2; //... 

y solo la llamada

 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. 

Prefiero preferir:

 @interface MyViewController : UIViewController @property (nonatomic, retain) IBOutletCollection(UIView) NSArray *inputFields; @end 

En el file NIB engancho los campos de text en el order deseado en este array inputFields. Después de eso hago una testing simple para el índice del UITextField que informa que el usuario tocó el retorno:

 // 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; } 
  si (celda == 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];  // Inicializa matriz mutable en ViewDidLoad
 }

 - (BOOL) textField ShouldReturn: (UITextField *) textField
 {

     int tag = (int) textField.tag;
     UITextField * txt = [self.array_Textfields objectAtIndex: label];
     [txt becomeFirstResponder];
     devolver SÍ;
 }

Tenía alnetworkingedor de 10+ UITextField en mi tablero de historia y la forma en que activé la siguiente funcionalidad fue creando una matriz de UITextField y convirtiendo al próximo UITextField en el primerResponedor. Aquí está el file de implementación:

 #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 

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.

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 } 

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]; }]; 

I've been using Michael G. Emmons' answer for about a year now, works great. I did notice recently that calling resignFirstResponder and then becomeFirstResponder immediately can cause the keyboard to "glitch", disappearing and then appearing immediately. I changed his version slightly to skip the resignFirstResponder if the nextField is available.

- (BOOL)textFieldShouldReturn:(UITextField *)textField
 { 

    if ([textField isKindOfClass:[NRTextField class]])
     {
        NRTextField *nText = (NRTextField*)textField;
        if ([nText nextField] != nil){
            dispatch_async(dispatch_get_main_queue(),
                           ^ { [[nText nextField] becomeFirstResponder];  });

         }
         más{
            [textField resignFirstResponder];
         }
     }
     más{
        [textField resignFirstResponder];
     }

     devuelve verdadero;

 }

you can use IQKeyboardManager library to do this. it handle every thing, you don't need any additional setup.IQKeyboardManager is available through CocoaPods, to install it simply add the following line to your Podfile:

 pod 'IQKeyboardManager' 

or Just drag and drop IQKeyBoardManager directory from demo project to your project. Eso es. you can find IQKeyBoardManager directory from https://github.com/hackiftekhar/IQKeyboardManager

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. 

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 } }