ios - poner - Cómo navegar a través de los campos de texto(botones Siguiente/Hecho)
como sacar el boton home del iphone 6 (30)
Acabo de crear un nuevo Pod cuando trato con estas cosas GNTextFieldsCollectionManager . Maneja automáticamente el problema del siguiente / último campo de texto y es muy fácil de usar:
[[GNTextFieldsCollectionManager alloc] initWithView:self.view];
Agarra todos los campos de texto ordenados por la jerarquía de vistas (o por etiquetas), o puede especificar su propia matriz de campos de texto.
¿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.
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.
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
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 con la acción (en su mayoría desconocida) UIControlEventEditingDidEndOnExit
UITextField
.
También puede conectar esto fácilmente en el guión gráfico, por lo que no se requiere delegación o código.
Edición: 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, que es una pena. Aún así, puede conectar todos sus campos de texto a una sola acción en su ViewController que luego determina qué campo de texto se becomeFirstResponder
en el Primer becomeFirstResponder
basado en el remitente (aunque no es tan elegante como la solución programática anterior, por lo que IMO lo hace con el código anterior en viewDidLoad
).
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:
- Todos los UITextField "tabbable" se encuentran en la misma vista principal.
- 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!
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.
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
yUITextView
, 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.
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
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
}
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;
}
}
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!
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.
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.
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;
}
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;
}
Tenía cerca de 10+ UITextField en mi panel de la historia y la forma en que habilité la siguiente funcionalidad fue crear una matriz de UITextField y hacer que el siguiente UITextField sea el primer Respuesta. 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
Un método muy fácil para descartar el teclado cuando se presiona el botón "Hecho" es:
Crea una nueva 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 llegue a vincular la acción IBA al campo de texto, enlace al evento ''Did End On Exit''.
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 menos el último campo y en "Listo" para el último campo, y cambiará el enfoque / descartará el teclado cuando estos se toquen.
Rápido <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: uso 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 generador de interfaces sin necesidad de configurar el delegado o usar view.tag
.
Todo lo que necesitas hacer es
- Configure el tipo de clase de su
UITextField
para que seaNextResponderTextField
- Luego, establezca la salida del
nextResponderField
para que apunte al siguiente respondedor, puede ser cualquier elementoUITextField
o cualquier subclaseUIResponder
. También puede ser un UIButton y la biblioteca es lo suficientemente inteligente como para activar el eventoTouchUpInside
del botón solo si está habilitado.
Aquí está la biblioteca en acción:
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 UIToolbar
para 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.
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
}
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];
}];
Solución en Swift 3.1, después de conectar sus campos de texto, los IBOutlets configuran su campo de texto delegado en viewDidLoad, y luego navegan su acción en 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
}
}
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.
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; }
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
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[[self.view viewWithTag:textField.tag+1] becomeFirstResponder];
return YES;
}
if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; txt_Input = [[ UITextField alloc] initWithFrame:CGRectMake(0, 10, 150, 30)]; txt_Input.tag = indexPath.row+1; [self.array_Textfields addObject:txt_Input]; // Initialize mutable array in ViewDidLoad } -(BOOL)textFieldShouldReturn:(UITextField *)textField { int tag = ( int) textField.tag ; UITextField * txt = [ self.array_Textfields objectAtIndex:tag ] ; [ txt becomeFirstResponder] ; return YES ; }