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.
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:
- tous "tabbable"
UITextField
s sont sur la même vue parent. - 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!
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
etUITextView
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.
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.
, 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.
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
).
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)
}
}
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
- définissez le type de classe de votre
UITextField
àNextResponderTextField
- puis régler la sortie du
nextResponderField
pour pointer vers le suivant répondeur, il peut être n'importe quoiUITextField
ou deUIResponder
sous-classe. Il peut aussi être UIButton et la Bibliothèque est assez intelligente pour déclencher l'événementTouchUpInside
du bouton seulement si elle est activée.
Voici la bibliothèque en action:
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.
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;
}
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
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)
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[[self.view viewWithTag:textField.tag+1] becomeFirstResponder];
return YES;
}
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
}
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.
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'.
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;
}
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
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;
}
}
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!
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.
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;
}
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 ; }
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
ç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.
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
}
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
}
}
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..
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.
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];
}];
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; }
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
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.