ios el - Cómo navegar a través de los campos de texto(botones Siguiente / Hecho)




desde touch (25)

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

¿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.

He configurado el IB los Botones (Siguiente / Hecho) pero ahora estoy bloqueado.

Implementé la acción textFieldShouldReturn pero ahora los botones Siguiente y Hecho cierran el teclado.


Esta es una solución simple en Swift, sin etiqueta, sin trucos de guión gráfico ...

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
    }

}

Y llámelo así (por ejemplo) con su delegado de campo de texto:

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    textField.nextTextFieldField()?.becomeFirstResponder()
    return true
}

en textFieldShouldReturn usted debe verificar que el campo de texto en el que se encuentra actualmente no sea el último cuando haga clic en siguiente y si no es así no descartar el teclado.


Aquí está una versión Swift 3 de la respuesta de Anth0 . ¡Lo estoy publicando aquí para ayudar a cualquier desarrollador veloz a querer aprovechar su gran respuesta! Me tomé la libertad de agregar un tipo de clave de retorno de "Siguiente" cuando configuró el objeto asociado.

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

Aquí hay otra extensión que muestra la posibilidad de usar el código anterior para recorrer una lista de UITextFields.

extension UIViewController: UITextFieldDelegate {
 public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
   guard let next = textField.nextTextField else {
     textField.resignFirstResponder()
     return true
   }

    next.becomeFirstResponder()
    return false
  }
}

Y luego, en su ViewController o donde sea, puede configurar sus campos de texto como ...

@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.

puede utilizar la biblioteca IQKeyboardManager para hacer esto. maneja cada cosa, no necesita ninguna configuración adicional. IQKeyboardManager está disponible a través de CocoaPods, para instalarlo simplemente agregue la siguiente línea a su Podfile:

pod 'IQKeyboardManager'

o Simplemente arrastre y suelte el directorio IQKeyBoardManager del proyecto de demostración a su proyecto. Eso es.puede encontrar el directorio IQKeyBoardManager en https://github.com/hackiftekhar/IQKeyboardManager


Hola a todos por favor ve 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;    
  }
}

Esto me funcionó 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<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 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.

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

Esto puede ser realmente un problema difícil de tratar ya que a menudo también querrá desplazar la pantalla o ajustar la posición del campo de texto para que sea fácil de ver cuando se edita. Solo asegúrese de realizar muchas pruebas para entrar y salir de los campos de texto de diferentes maneras y también para salir temprano (siempre dé al usuario la opción de descartar el teclado en lugar de ir al siguiente campo, generalmente con "Hecho" en la barra de navegación)


En Cocoa para Mac OS X, tiene la siguiente cadena de respondedores, donde puede preguntar al campo de texto qué control debería tener a continuación. Esto es lo que hace que el tabulado entre campos de texto funcione. Pero como los dispositivos iOS no tienen teclado, solo el tacto, 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 "tabbable" se encuentran en la misma vista principal.
  2. Su "orden de tabulación" está definido por la propiedad de etiqueta.

Suponiendo que pueda anular textFieldShouldReturn: como esto:

-(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 se pueden ignorar.

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 vista del campo de texto será un UITableViewCell, el siguiente respondedor será

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

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

Para resolver esto (y porque odio confiar en las etiquetas para hacer cosas) decidí agregar una propiedad personalizada al objeto UITextField. En otras palabras, creé 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, aquí está cómo 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 implementa 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 enlazada de UITextField, cada uno sabiendo quién es el siguiente en la línea.

Espero que te ayude.


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 texto OSX donde un campo de texto sabe dónde debe ir el enfoque a continuación
  • No se basa en establecer o usar etiquetas, que son IMO frágiles para este caso de uso
  • Se puede extender para trabajar con los controles UITextField y UITextView , o con cualquier control de UI de entrada del teclado
  • No desordena el controlador de vista con el código delegado de UITextField repetitivo
  • Se integra muy bien con IB y se puede configurar a través de la opción familiar de arrastrar y soltar para conectar salidas.

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 . A continuación, también en IB, configure el delegado para cada uno de los 'SOTextFields' a 'File's Owner' (que está justo donde colocó el código para el método del delegado - textFieldShouldReturn). La belleza de este diseño es que ahora puede simplemente hacer clic con el botón derecho en cualquier campo de texto y asignar la siguiente salida de campo al siguiente objeto SOTextField que desea que sea el siguiente respondedor.

Además, puedes hacer cosas geniales como hacer un loop en los campos de texto para que después de que el último pierda el enfoque, el primero vuelva a recibir el enfoque.

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


Una forma más consistente y robusta es usar NextResponderTextField . Puede configurarlo totalmente desde el generador de interfaces sin necesidad de configurar el delegado o usar view.tag .

Todo lo que necesitas hacer es

  1. Configure el tipo de clase de su UITextField para que sea NextResponderTextField
  2. Luego, establezca la salida del nextResponderField para que apunte al siguiente respondedor, puede ser cualquier elemento UITextField o cualquier subclase 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.

Aquí está la biblioteca en acción:


Prefiero preferir

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

En el archivo NIB engancho los 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 pulsó devolver:

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

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

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

Así que esto es lo que he encontrado. Su formulario debe ser administrado por un controlador de vista, y los controladores de vista son parte de la cadena de respuesta. Entonces 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 desplazar a los respondedores fuera de la pantalla que están visibles.

Otra ventaja de este enfoque es que no necesita subclasificar todos los tipos de controles que desee mostrar (como UITextField s) sino que puede administrar la lógica en el nivel del controlador, donde, seamos honestos, es el lugar correcto para hacerlo asi que.


Sin etiquetas de uso y sin agregar una propiedad para nextField / nextTextField, puede intentar esto para emular TAB, donde "testInput" es su campo activo actual:

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

Me gustan las soluciones OO que Anth0 y Answerbot ya han sugerido. Sin embargo, estaba trabajando en un POC rápido y pequeño, por lo que no quería saturar las cosas con subclases y categorías.

Otra solución simple es crear una NSArray de campos y buscar el siguiente campo cuando presione siguiente. No es una solución OO, pero es rápida, simple y fácil de implementar. Además, puede ver y modificar el pedido 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 devuelvo NO porque no quiero insertar un salto de línea. Pensé en señalarlo, ya que cuando respondiera SÍ, saldría automáticamente de los campos siguientes o insertaría un salto de línea en mi TextView. Me tomó un poco de tiempo para darme cuenta de eso.
  • activeField realiza un seguimiento del campo activo en caso de que sea necesario desplazarse para despejar el campo desde el teclado. 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 activará el evento KeyboardWasShown inmediatamente.

Esta es una publicación antigua, pero tiene un alto rango de páginas, por lo que voy a añadir mi solución.

Tuve un problema similar y terminé creando una subclase UIToolbarpara administrar la funcionalidad siguiente / anterior / terminada en una tabla dinámica con secciones: https://github.com/jday001/DataEntryToolbar

Establece la barra de herramientas como inputAccessoryView de sus campos de texto y los agrega a su diccionario. Esto le permite recorrerlos hacia adelante y hacia atrás, incluso con contenido dinámico. Existen métodos de delegado si desea activar su propia funcionalidad cuando ocurre la navegación de textField, pero no tiene que lidiar con la administración de ninguna etiqueta o el estado del primer respondedor.

Hay fragmentos de código y una aplicación de ejemplo en el enlace de GitHub para ayudar con los detalles de la implementación. Necesitará su propio modelo de datos para realizar un seguimiento de los valores dentro de los campos.


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

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

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

class ViewController: UIViewController,UITextFieldDelegate  

Agregue el campo 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 en función del número de etiqueta incremental que se le asigna.

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 teclado se muestre como Next , también tiene otras opciones como Join/Go , etc., según su aplicación, cambiar 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 la etiqueta

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
 }

Primero configure la tecla de retorno del teclado 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;
}

Aquí hay una implementación de tabulación 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 los de UITextField . También funciona a la perfección con Interface Builder y guiones gráficos.

Fuente y aplicación de muestra: repositorio de GitHub para UIControlsWithTabbing

Uso:

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

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

He estado usando la respuesta de Michael G. Emmons por cerca de un año, funciona muy bien. Noté recientemente que llamar a resignFirstResponder y luego convertirme en First Responder inmediatamente puede hacer que el teclado "parpadee", desapareciendo y luego aparezca inmediatamente. Cambié un poco su versión para omitir resignFirstResponder si el nextField está disponible.

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

    return true;

}

Intenté 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!


He agregado a la respuesta de PeyloW en caso de que desee 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 subclasificas la vista de esta manera:

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

Swift 4.1:
extension UINavigationController {
   override open var disablesAutomaticKeyboardDismissal: Bool {
      return false
   }
}






ios objective-c iphone