Cómo navegar a través de los campos de texto (Botones Siguiente / Hecho)

¿Cómo puedo navegar por todos mis campos de texto con el botón “Siguiente” en el teclado del iPhone?

El último campo de texto debe cerrar el Teclado.

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

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

En Cocoa para Mac OS X, tiene la siguiente cadena de respuesta, donde puede preguntar al campo de texto qué control debería tener el siguiente enfoque. Esto es lo que hace que las tabulaciones entre los campos de texto funcionen. Pero dado que los dispositivos con iOS no tienen teclado, solo táctil, este concepto no ha sobrevivido a la transición a Cocoa Touch.

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

  1. Todos los UITextField s “tabbables” están en la misma vista principal.
  2. Su “orden de tabulación” está definido por la propiedad de etiqueta.

Asumiendo 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 las suposiciones también pueden ser ignoradas.

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 } 

Si la supervista del campo de texto será una UITableViewCell, el próximo respondedor será

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

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

  • Más cerca de la implementación del campo de texto OSX donde un campo de texto sabe hacia dónde debe dirigirse el foco
  • No se basa en establecer o usar tags, que son, IMO frágiles para este caso de uso
  • Se puede ampliar para que funcione con los controles UITextField y UITextView , o con cualquier control de interfaz de usuario de entrada de teclado
  • No satura su controlador de vista con un código de delegado UITextField
  • Se integra muy bien con IB y se puede configurar mediante la opción familiar, arrastrar y soltar para conectar tomas de stream.

Cree una subclase UITextField que tenga una propiedad IBOutlet llamada 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 su controlador de vista, creará el método -textFieldShouldReturn: delegate:

 - (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, cambie sus UITextFields para usar la clase SOTextField . Luego, también en IB, establezca el delegado para cada uno de los ‘SOTextFields’ en ‘File’s Owner’ (que es justo donde coloca el código para el método de delegado – textFieldShouldReturn). La belleza de este diseño es que ahora simplemente puede hacer clic derecho en cualquier campo de texto y asignar el siguiente campo de salida al próximo objeto SOTextField que desea ser el siguiente respondedor.

Asignando nextField en IB

Además, puedes hacer cosas geniales como recorrer los campos de texto para que, una vez que el último pierda el foco, el primero reciba el foco otra vez.

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

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

Para resolver esto (y porque odio depender de tags para hacer cosas) decidí agregar una propiedad personalizada al objeto UITextField. En otras palabras, creé una categoría en UITextField de esta manera:

UITextField + Extended.h

 @interface UITextField (Extended) @property(retain, nonatomic)UITextField* nextTextField; @end 

UITextField + Extended.m

 #import "UITextField+Extended.h" #import  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 implemente 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 lista vinculada de UITextField, cada uno sabe quién es el siguiente en la línea.

Espero que ayude

Aquí hay uno sin delegación:

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

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

También puede conectarlo fácilmente en el guión gráfico, por lo que no se requiere delegación o 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 evento de control, lo cual es una lástima. Aún así, puede conectar todos sus campos de texto 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 hacer esto 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 botón de retorno en "Siguiente" para todos los campos excepto en el último y en "Hecho" para el último campo, y desplace el foco / cierre el teclado 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: usar 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 forma más consistente y robusta es usar NextResponderTextField . Puede configurarlo totalmente desde el constructor de interfaces sin necesidad de configurar el delegado o usar view.tag .

Todo lo que necesitas hacer es

  1. Establezca el tipo de clase de su UITextField para que sea NextResponderTextField enter image description here
  2. Luego configure la salida del nextResponderField para apuntar al siguiente respondedor, puede ser cualquier cosa UITextField o cualquier subclase de UIResponder . También puede ser un UIButton y la biblioteca es lo suficientemente inteligente como para activar el evento TouchUpInside del botón solo si está habilitado. enter image description hereenter image description here

Aquí está la biblioteca en acción:

enter image description here

Me gustan las soluciones 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 complicar las cosas con subclases y categorías.

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

Aquí está mi código (basado en 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 devuelvo NO porque no quiero insertar un salto de línea. Solo pensé en señalar eso ya que cuando devolvía SÍ automáticamente salía de los campos subsiguientes o insertaba un salto de línea en mi TextView. Me tomó un poco de tiempo darme cuenta de eso.
  • activeField realiza un seguimiento del campo activo en caso de que sea necesario desplazarse para despejar el campo del teclado. Si tiene un código similar, asegúrese de asignar el campo activo antes de cambiar el primer respondedor. El cambio del primer respondedor es inmediato y activará el evento KeyboardWasShown inmediatamente.

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

Aplicación de origen y ejemplo: repository de GitHub para UIControlsWithTabbing

Uso:

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

Asignando nextControl en Interface Builder

Encabezamiento:

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

Implementación:

 #import "UIControl+NextControl.h" #import  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 texto, llama a [otherTextField becomeFirstResponder] y el siguiente campo se enfoca.

En realidad, este puede ser un problema difícil de manejar, ya que a menudo también querrás desplazarte por la pantalla o ajustar la posición del campo de texto para que sea fácil de ver al editar. Solo asegúrate de hacer muchas pruebas entrando y saliendo de los campos de texto de diferentes maneras y también saliendo temprano (siempre dale al usuario la opción de cerrar el teclado en lugar de ir al siguiente campo, generalmente con “Hecho” en la barra de navegación)

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

He intentado muchos códigos y, finalmente, esto funcionó para mí en Swift 3.0. Última [marzo de 2017]

La clase ViewController debe heredarse UITextFieldDelegate para que este código funcione.

 class ViewController: UIViewController,UITextFieldDelegate 

Agregue el campo de texto con el número de etiqueta adecuado y este número de etiqueta se usa para llevar el control al campo de texto apropiado según el número de etiqueta incremental que se le haya asignado.

 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 Key return vuelva a mostrarse como Next , también tiene otras opciones como Join/Go , etc., según su aplicación, 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 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 } 

Me sorprende la cantidad de respuestas que aquí no entienden un concepto simple: navegar por los controles en su aplicación no es algo que las vistas deberían hacer. El trabajo del controlador es decidir qué control convertir en el siguiente primer respondedor.

Además, la mayoría de las respuestas solo se aplica a la navegación hacia adelante, pero los usuarios también pueden querer retroceder.

Así que esto es lo que se me ocurrió. Su formulario debe ser administrado por un controlador de vista, y los controladores de vista son parte de la cadena de respuesta. Así que eres perfectamente libre de implementar los siguientes métodos:

 #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 una lógica adicional para el desplazamiento de respondedores fuera de la pantalla visible de antemano.

Otra ventaja de este enfoque es que no es necesario que subclasses todos los tipos de controles que desee mostrar (como UITextField s), pero en su lugar puede gestionar la lógica en el nivel de controlador, donde, seamos honestos, es el lugar adecuado para hacer asi que.

Un método muy fácil para descartar el teclado cuando se presiona el botón ‘Listo’ es:

Crea un nuevo IBAction en el encabezado

 - (IBAction)textFieldDoneEditing:(id)sender; 

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

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

Luego, cuando vincule el IBAction con el campo de texto, enlace al evento ‘Did End On Exit’.

Primero configure la clave de retorno del teclado en xib; de lo contrario, puede escribir el 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; } 

He agregado la respuesta de PeyloW en caso de que esté buscando implementar una funcionalidad de botón 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 subclasifica la UIView de esta manera:

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

Hola a todos, por favor, mira esto

 - (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 etiqueta único que se puede recuperar más adelante: activate-next-uitextfield-in-uitableview-ios

¡Espero que esto ayude!

Acabo de crear un nuevo Pod cuando trato con este material GNTextFieldsCollectionManager . Maneja automáticamente el siguiente / último problema de TextField y es muy fácil de usar:

 [[GNTextFieldsCollectionManager alloc] initWithView:self.view]; 

Toma todos los campos de texto ordenados apareciendo en la jerarquía de vista (o por tags), o puede especificar su propia matriz de textFields.

Prefiero:

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

En el archivo NIB engancho textFields en el orden deseado en esta matriz inputFields. Después de eso hago una prueba simple para el índice del UITextField que informa que el usuario tocó 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];  // Inicializa la matriz mutable en ViewDidLoad
 }

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

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

Tenía aproximadamente 10+ UITextField en mi storyboard y la forma en que habilité la siguiente funcionalidad fue creando una matriz de UITextField y convirtiendo el siguiente UITextField en el primer Respondedor. Aquí está el archivo 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 

Esto funcionó para mí en Xamarin.iOS / Monotouch. Cambie el botón del teclado a Siguiente, pase el control al siguiente UITextField y oculte el teclado después del último UITextField.

 private void SetShouldReturnDelegates(IEnumerable 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 tus TextFields no tienen una etiqueta, configúralo 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. 

Esta es una solución simple, rápida, sin tags, sin trucos de guiones gráficos …

Solo usa esta extensión:

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

         }
        else{
            [textField resignFirstResponder];
         }
     }
    else{
        [textField resignFirstResponder];
     }

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