Comment naviguer dans les champs de texte (boutons Suivant / fait))

Comment puis-je naviguer dans tous mes champs de texte avec le bouton "Suivant" sur le clavier de l'iPhone?

Le dernier champ de texte doit fermer le Clavier.

j'ai configuré les boutons IB (Next / Done) mais maintenant je suis coincé.

j'ai mis en œuvre le textFieldShouldReturn action mais maintenant le prochain et fait boutons fermer le clavier.

462
demandé sur picciano 2009-08-28 19:34:40

30 réponses

dans Cocoa for Mac OS X, vous avez la chaîne responder suivante, où vous pouvez demander au champ de texte quel contrôle devrait avoir focus next. C'est ce qui fait fonctionner le tabbing entre les champs de texte. Mais comme les appareils iOS n'ont pas de clavier, seulement du toucher, ce concept n'a pas survécu à la transition vers Cocoa Touch.

cela peut être facilement fait de toute façon, avec deux hypothèses:

  1. tous "tabbable" UITextField s sont sur la même vue parent.
  2. Leurs onglet "ordre" est défini par la propriété tag.

en supposant que cela, vous pouvez outrepasser textFieldShouldReturn: comme ceci:

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

Ajouter un peu plus de code, et les hypothèses peuvent être ignorées aussi bien.

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 le superview du champ de texte sera un utilitaire Viewcell, alors le prochain répondeur sera

let nextResponder = textField.superview?.superview?.superview?.viewWithTag(nextTag) as UIResponder!
546
répondu PeyloW 2018-03-09 12:58:49

Il ya un beaucoup solution plus élégante qui m'a soufflé la première fois que je l'ai vu. Avantages:

  • plus Proche de OSX textfield mise en œuvre lorsqu'un textfield sait où l'accent devrait aller
  • ne repose pas sur le réglage ou l'utilisation d'étiquettes -- qui sont, IMO fragile pour ce cas d'utilisation
  • peut être étendu pour fonctionner à la fois avec les commandes UITextField et UITextView ou toute contrôle D'entrée du clavier IU
  • n'embrouille pas votre contrôleur de vue avec le code délégué de boilerplate UITextField
  • S'intègre parfaitement avec IB et peut être configuré via l'option familière-drag-drop pour connecter les prises.

créer une sous-classe UITextField qui possède une propriété IBOutlet appelée nextField. Voici l'en-tête:

@interface SOTextField : UITextField

@property (weak, nonatomic) IBOutlet UITextField *nextField; 

@end

et voici la mise en œuvre:

@implementation SOTextField

@end

dans votre contrôleur de vue, vous allez créer la -textFieldShouldReturn: méthode du délégué:

- (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, changez vos champs UITextFields pour utiliser la classe SOTextField . Ensuite, toujours en IB, définissez le délégué pour chacun des "SOTextFields" au "propriétaire du fichier" (ce qui est juste là où vous mettez le code pour la méthode delegate - textFieldShouldReturn). La beauté de ce design est que maintenant vous pouvez tout simplement droit-cliquez sur n'importe quel textField et assignez le sortie nextField à l'objet suivant SOTextField vous voulez être le prochain intervenant.

Assigning nextField in IB

de plus, vous pouvez faire des choses fraîches comme boucler les champs de texte de sorte qu'après la dernière perte de mise au point, la première recevra de nouveau la mise au point.

ce champ peut facilement être étendu pour attribuer automatiquement le returnKeyType du SOTextField à un UIReturnKeyNext s'il y a une autre zone assignée -- une de moins chose configurer manuellement.

169
répondu memmons 2015-10-27 16:37:49

, Voici ma solution pour ce problème.

pour résoudre ce problème (et parce que je déteste me fier aux tags pour faire des choses) j'ai décidé d'ajouter une propriété personnalisée à L'objet UITextField. En d'autres termes, j'ai créé une catégorie sur UITextField comme ceci:

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

Maintenant, voici comment je l'utilise :

UITextField *textField1 = ...init your textfield
UITextField *textField2 = ...init your textfield
UITextField *textField3 = ...init your textfield

textField1.nextTextField = textField2;
textField2.nextTextField = textField3;
textField3.nextTextField = nil;

et mettre en œuvre la méthode textFieldShouldReturn:

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

    UITextField *next = theTextField.nextTextField;
    if (next) {
        [next becomeFirstResponder];
    } else {
        [theTextField resignFirstResponder];
    }

    return NO; 
}

j'ai maintenant une sorte de liste liée D'UITextField, chacun sachant qui est le prochain dans la ligne.

J'espère que ça aidera.

78
répondu Anth0 2011-12-01 16:34:18

En voici un sans délégation:

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

Fonctionne à l'aide de l' (la plupart du temps inconnue) UIControlEventEditingDidEndOnExit UITextField action.

vous pouvez aussi facilement le brancher dans le storyboard, de sorte qu'aucun code de délégation ou n'est nécessaire.

Edit: en fait, je ne peux pas trouver comment l'accrocher dans storyboard. becomeFirstResponder ne semble pas être une action offert pour cet événement de contrôle, ce qui est dommage. Néanmoins, vous pouvez accrocher tous vos champs de texte jusqu'à une seule action dans votre ViewController qui détermine ensuite quel champ de texte à becomeFirstResponder basé sur l'expéditeur (bien qu'alors il ne soit pas aussi élégant que la solution programmatique ci-dessus afin IMO le faire avec le code ci-dessus dans viewDidLoad ).

75
répondu mxcl 2017-10-25 22:24:25

une extension swift qui applique la réponse de mxcl pour rendre cela particulièrement facile (adapté à swift 2.3 par 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)
    }
}

c'est facile à utiliser:

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

l'extension positionnera le bouton de retour à" Next "pour tous les champs sauf le dernier et à" Done " pour le dernier champ, et déplacera le focus / rejettera le clavier lorsque ceux-ci sont activés.

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: utiliser comme ceci -

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)
        }
    }
43
répondu Amos Joshua 2016-10-06 20:49:22

une façon plus cohérente et plus robuste est d'utiliser Nextreprendertextfield Vous pouvez le configurer totalement à partir de interface builder sans avoir besoin de configurer le délégué ou d'utiliser view.tag .

Tout ce que vous devez faire est de

  1. définissez le type de classe de votre UITextField à NextResponderTextField enter image description here
  2. puis régler la sortie du nextResponderField pour pointer vers le suivant répondeur, il peut être n'importe quoi UITextField ou de UIResponder sous-classe. Il peut aussi être UIButton et la Bibliothèque est assez intelligente pour déclencher l'événement TouchUpInside du bouton seulement si elle est activée. enter image description here enter image description here

Voici la bibliothèque en action:

enter image description here

25
répondu mohamede1945 2015-06-29 04:39:09

j'aime l'OO solutions qui ont déjà été suggéré par Anth0 et Answerbot. Cependant, je travaillais sur un POC rapide et petit, donc je ne voulais pas encombrer les choses avec des sous-classes et des catégories.

une autre solution simple est de créer un NSArray de champs et de rechercher le champ suivant lorsque vous appuyez sur Suivant. Pas une solution OO, mais rapide, simple et facile à mettre en œuvre. Aussi, vous pouvez voir et modifier la commande en un coup d'œil.

Voici mon code (construit sur d'autres réponses dans ce fil):

@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;
}
  • je renvoie toujours non parce que je ne veux pas d'une coupure de ligne insérée. J'ai juste pensé que je ferais remarquer que depuis que j'ai retourné oui, il serait automatiquement sortir les champs suivants ou insérer une rupture de ligne dans mon TextView. Il m'a fallu un peu de temps pour comprendre cela.
  • activeField garde trace du secteur actif au cas où le défilement est nécessaire pour détacher le secteur du clavier. Si vous avez un code similaire, assurez-vous d'assigner le champ activeField avant de changer le premier intervenant. Le changement de premier intervenant est immédiat et déclenchera immédiatement L'événement KeyboardWasShown.
14
répondu Marquee 2012-05-31 15:12:18

Voici une implémentation de tabbing utilisant une catégorie sur UIControl. Cette solution a tous les avantages des méthodes de Michael et Anth0, mais fonctionne pour tous les UIControls, pas seulement UITextField s. Il fonctionne également de manière transparente avec Interface Builder et storyboards.

source et échantillon app: GitHub repository for UIControlsWithTabbing

Utilisation:

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

Assigning nextControl in Interface Builder

en-tête:

//
// UIControl+NextControl.h
// UIControlsWithTabbing
//

#import <UIKit/UIKit.h>

@interface UIControl (NextControl)

@property (nonatomic, weak) IBOutlet UIControl *nextControl;

- (BOOL)transferFirstResponderToNextControl;

@end

mise en œuvre:

#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
11
répondu picciano 2017-09-22 17:13:31

après avoir quitté un champ de texte, vous appelez [otherTextField devient premier répondeur] et le champ suivant se focalise.

cela peut en fait être un problème délicat à traiter puisque souvent vous voudrez également faire défiler l'écran ou autrement ajuster la position du champ de texte afin qu'il soit facile à voir lors de l'édition. Assurez-vous juste de faire beaucoup de tests avec l'entrée et la sortie des champs de texte de différentes façons et aussi en partant tôt (toujours donner à l'utilisateur une option pour rejeter le clavier au lieu d'aller au champ suivant, habituellement avec "Done" dans la barre de navigation)

9
répondu Kendall Helmstetter Gelner 2009-08-28 20:19:58
 -(BOOL)textFieldShouldReturn:(UITextField *)textField
{
   [[self.view viewWithTag:textField.tag+1] becomeFirstResponder];
   return YES;
}
9
répondu iKushal 2012-08-24 10:42:05

j'ai essayé de nombreux codes et finalement, cela a fonctionné pour moi dans Swift 3.0 dernier [mars 2017]

la classe ViewController doit être héritée du UITextFieldDelegate pour faire fonctionner ce code.

class ViewController: UIViewController,UITextFieldDelegate  

ajouter le champ de texte avec le numéro D'étiquette approprié et ce numéro d'étiquette est utilisé pour prendre le contrôle du champ de texte approprié basé sur le numéro d'étiquette incrémental qui lui est assigné.

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

dans le code ci-dessus, le returnKeyType = UIReturnKeyType.next où fera la touche de retour clavier pour afficher comme Next vous avez également d'autres options comme Join/Go etc, basé sur votre application changer les valeurs.

Ce textFieldShouldReturn est une méthode de UITextFieldDelegate contrôlé et nous avons ici à côté de terrain de la sélection fondée sur le Tag de la valeur d'incrémentation

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
 }
8
répondu BHUVANESH MOHANKUMAR 2017-08-16 15:30:30

je suis surpris par le nombre de réponses ici ne parviennent pas à comprendre un concept simple: naviguer à travers les contrôles dans votre application n'est pas quelque chose que les vues elles-mêmes devraient faire. C'est le travail du contrôleur de décider quel contrôle faire le prochain premier intervenant.

la plupart des réponses ne s'appliquent qu'à la navigation en avant, mais les utilisateurs peuvent aussi vouloir revenir en arrière.

voilà ce que j'ai trouvé. Votre formulaire doit être géré par un contrôleur de vue, et les contrôleurs de vue font partie de la chaîne de responder. Vous êtes donc parfaitement libre de mettre en œuvre les méthodes suivantes:

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

une logique supplémentaire de défilement des répondants visibles à l'avance peut s'appliquer.

un autre avantage de cette approche est que vous n'avez pas besoin de sous-classe toutes sortes de contrôles que vous pouvez vouloir afficher (comme UITextField s) , mais peut gérer la logique au niveau du contrôleur, où, soyons honnêtes, est le bon endroit pour le faire.

7
répondu Christian Schnorr 2015-06-16 17:28:49

une méthode très simple pour rejeter le clavier lorsque le bouton "fait" est pressé est:

créer une nouvelle IBAction dans l'en-tête

- (IBAction)textFieldDoneEditing:(id)sender;

Dans le fichier d'implémentation (.m) ajouter la méthode suivante:

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

puis, lorsque vous venez de lier L'IBAction à l'événement textfield - link à L'événement 'Did End On Exit'.

6
répondu jcrowson 2012-03-23 09:54:07

première touche de retour clavier définie dans xib, sinon vous pouvez écrire le code dans 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;
}
6
répondu mahesh chowdary 2015-03-03 21:34:28

j'ai ajouté à la réponse de PeyloW dans le cas où vous cherchez à mettre en œuvre une fonctionnalité de bouton Précédent/Suivant:

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

    }
}

où vous sous-classe L'UIView comme ceci:

@implementation UIView (FindAndReturnFirstResponder)
- (UITextView *)findFirstResponderAndReturn
{
    for (UITextView *subView in self.subviews) {
        if (subView.isFirstResponder){
            return subView;
        }
    }
    return nil;
}
@end
4
répondu KronoS 2012-08-24 10:42:37

Bonjour à tous s'il vous plaît voir celui-ci

- (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;    
  }
}
4
répondu rithik 2012-08-24 10:43:39

j'ai essayé de résoudre ce problème en utilisant une approche plus sophistiquée basée sur l'assignation de chaque cellule (ou UITextField ) dans un UITableView une valeur d'étiquette unique qui peut être récupéré plus tard: activer la-prochaine-uitextfield-en-uitableview-ios

j'espère que cela aidera!

4
répondu Fabiano Francesconi 2013-06-14 12:04:17

je viens de créer un nouveau Pod pour traiter ce genre de choses GNTextFieldsCollectionManager . Il traite automatiquement le problème suivant / dernier textField et est très facile à utiliser:

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

saisit tous les champs de texte triés en apparaissant dans la hiérarchie des vues (ou par tags), ou vous pouvez spécifier votre propre tableau de champs de texte.

4
répondu JakubKnejzlik 2015-08-21 10:24:20

je préfère plutôt:

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

dans le fichier NIB j'accroche les champs de texte dans l'ordre désiré dans ce tableau inputFields. Après cela je fais un test simple pour l'index de L'UITextField qui rapporte que l'utilisateur tapped retour:

// 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;
}
3
répondu Anticro 2013-08-26 09:34:38
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 ;
}
3
répondu Rebecca Curties 2014-08-01 10:04:31

j'avais environ 10+ UITextField dans mon story board et la façon dont j'ai activé la fonctionnalité next était en créant un tableau D'UITextField et en faisant de la prochaine UITextField le premier répondant. Voici le fichier d'implémentation:

#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
3
répondu Illegal Argument 2014-11-04 10:06:07

ça a marché pour moi à Xamarin.iOS / Monotouch. Changez le bouton clavier en Next, passez la commande à L'UITextField suivant et cachez le clavier après le dernier 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.
    };
  }
}

dans le ViewDidLoad vous aurez:

si vos champs de texte n'ont pas d'étiquette, définissez-le maintenant:

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

et juste l'appel

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.
3
répondu Daniele D. 2016-02-16 16:27:44

il s'agit d'une solution simple dans swift, sans étiquette à l'aide, pas de trucs de story-board...

il suffit d'utiliser cette extension:

extension UITextField{

    func nextTextFieldField() -> UITextField?{
        //field to return
        var returnField : UITextField?
        if self.superview != nil{
            //for each view in superview
            for (_, view) in self.superview!.subviews.enumerate(){
                //if subview is a text's field
                if view.isKindOfClass(UITextField){
                    //cast curent view as text field
                    let currentTextField = view as! UITextField
                    //if text field is after the current one
                    if currentTextField.frame.origin.y > self.frame.origin.y{
                        //if there is no text field to return already
                        if returnField == nil {
                            //set as default return
                            returnField = currentTextField
                        }
                            //else if this this less far than the other
                        else if currentTextField.frame.origin.y < returnField!.frame.origin.y{
                            //this is the field to return
                            returnField = currentTextField
                        }
                    }
                }
            }
        }
        //end of the mdethod
        return returnField
    }

}

et appelez-le comme ceci (par exemple) avec votre délégué textfield:

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    textField.nextTextFieldField()?.becomeFirstResponder()
    return true
}
3
répondu Kevin ABRIOUX 2016-07-02 11:03:37

Solution dans Swift 3.1, après avoir connecté vos textfields IBOutlets définir votre délégué textfields dans viewDidLoad, puis naviguer dans votre action dans 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
        }

    }
3
répondu Krishna Kumar 2017-04-25 08:06:44

dans textFieldShouldReturn vous devez vérifier que le champ de texte sur lequel vous êtes actuellement n'est pas le dernier quand ils cliquent après et si son ne pas rejeter le clavier..

2
répondu Daniel 2009-08-28 15:49:38

il s'agit d'un ancien post, mais a un rang élevé de page donc je vais répondre avec ma solution.

j'ai eu un problème similaire et j'ai fini par créer une sous-classe de UIToolbar pour gérer la fonctionnalité next / previous/done dans un tableView dynamique avec des sections: https://github.com/jday001/DataEntryToolbar

vous définissez la barre d'outils comme inputAccessoryView de vos champs de texte et les ajoutez à son dictionnaire. Cela vous permet de faire du vélo à travers eux, en avant et en arrière, même avec du contenu dynamique. Il y a des méthodes de délégation si vous voulez déclencher votre propre fonctionnalité lorsque la navigation textField se produit, mais vous n'avez pas à gérer les étiquettes ou le statut de premier intervenant.

il y a des extraits de code et un exemple d'application sur le lien GitHub pour vous aider avec les détails de la mise en œuvre. Vous aurez besoin de votre propre modèle de données pour suivre les valeurs dans les champs.

2
répondu jday 2015-01-26 21:35:50

sans utiliser de balises et sans ajouter de propriété pour nextField / nextTextField, vous pouvez essayer ceci pour émuler L'onglet, où "testInput" est votre champ actif actuel:

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];
                                                    }];
2
répondu Cœur 2015-02-14 11:47:28

J'utilise la réponse de Michael G. Emmons depuis environ un an, ça marche très bien. J'ai remarqué récemment que le fait d'appeler resignFirstResponder et de devenir alors premier responder immédiatement peut causer un "bug" du clavier, disparaître et apparaître immédiatement. J'ai légèrement modifié sa version pour sauter le resignFirstResponder si le prochain champ 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;

}
2
répondu arinmorf 2015-03-18 02:34:44

vous pouvez utiliser IQKeyboardManager bibliothèque pour ce faire. il gère chaque chose, vous n'avez pas besoin de configuration supplémentaire.IQKeyboardManager est disponible via CocoaPods, pour l'installer il suffit d'ajouter la ligne suivante à votre Podfile:

pod 'IQKeyboardManager'

ou Il suffit de glisser-déposer IQKeyBoardManager répertoire de projet de démonstration à votre projet. C'est tout. vous pouvez trouver L'Annuaire de IQKeyBoardManager de https://github.com/hackiftekhar/IQKeyboardManager

2
répondu Amit Shelgaonkar 2015-06-22 12:42:46

Voici une version Swift 3 de Anth0 'S réponse. Je le poste ici pour aider tous les développeurs swift à vouloir profiter de sa grande réponse! J'ai pris la liberté d'ajouter une touche de retour de type "Suivant" lorsque vous définissez l'objet associé.

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

Voici une autre extension qui montre une possibilité d'utiliser le code ci-dessus pour parcourir une liste de champs UITextFields.

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

    next.becomeFirstResponder()
    return false
  }
}

Et puis dans votre ViewController ou n'importe où, vous pouvez configurer vos champs de texte comme ça...

@IBOutlet fileprivate weak var textfield1: UITextField!
@IBOutlet fileprivate weak var textfield2: UITextField!
@IBOutlet fileprivate weak var textfield3: UITextField!

...

[textfield1, textfield2, textfield3].forEach{ "151920920"?.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.
2
répondu Justin Wright 2017-02-23 15:03:15