web-dev-qa-db-fra.com

Basculer entre les champs de texte en appuyant sur la touche Retour dans Swift

Je conçois une application iOS et je souhaite que lorsque la touche de retour est enfoncée dans mon iPhone, elle me renvoie au champ de texte suivant.

J'ai trouvé quelques questions similaires, avec d'excellentes réponses, mais elles se trouvent toutes dans Objective-C et je recherche le code Swift. Voici ce que j'ai jusqu'à présent:

func textFieldShouldReturn(emaillabel: UITextField) -> Bool{
    return true
}

Il est placé dans le fichier qui est connecté et contrôleur à UIView qui contient les champs de texte, mais je ne suis pas sûr que ce soit le bon endroit.

Je suis fondamentalement nouveau chez Swift, alors expliquez-moi chaque petit pas ou je vais réussir à tout gâcher. J'utilise aussi la dernière version de Xcode si cela fait une différence.

d'accord, j'ai donc essayé et obtenu l'erreur suivante:
//could not find an overload for '!=' that accepts the supplied arguments

func textFieldShouldReturn(textField: UITextField) -> Bool {
    let nextTag: NSInteger = textField.tag + 1;
    // Try to find next responder
    let nextResponder: UIResponder = textField.superview!.viewWithTag(nextTag)!
    if (nextResponder != nil) {//could not find an overload for '!=' that accepts the supplied arguments

        // Found next responder, so set it.
        nextResponder.becomeFirstResponder()
    } else {
        // Not found, so remove keyboard.
        textField.resignFirstResponder()
    }
    return false; // We do not want UITextField to insert line-breaks.
}

Merci d'avance les copains !!

45
lucas rodriguez

Swift 3.0 (vérifiez l'historique d'édition pour les versions précédentes):

class ViewController: UIViewController,UITextFieldDelegate 
{
   //Link each UITextField
   @IBOutlet weak var textField: UITextField!

   override func viewDidLoad() 
   {
      super.viewDidLoad()
      // Do this for each UITextField
      textField.delegate = self
      textField.tag = 0 //Increment accordingly
   }

   func textFieldShouldReturn(_ textField: UITextField) -> Bool 
   {
      // Try to find next responder
      if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
         nextField.becomeFirstResponder()
      } else {
         // Not found, so remove keyboard.
         textField.resignFirstResponder()
      }
      // Do not add a line break
      return false
   }
}

Assurez-vous que vos délégués UITextField sont définis et que les balises sont incrémentées correctement. Cela peut également être effectué via Interface Builder.

Voici un lien vers un article d'Obj-C que j'ai trouvé: Comment naviguer dans les champs de texte (boutons Suivant/Terminé)

117
Caleb

Swift 4

Vous pouvez facilement passer à un autre TextField. 

  • Ajoutez UITextFieldDelegate et ajoutez la méthode textFieldShouldReturn(_:) dans ViewController  
  • Faites glisser de TextField à ViewController in Interface Builder . Puis sélectionnez la propriété delegate. Note : Faites ceci pour tous les TextField
  • Créer une IBOutlet pour tous TextFields

    class ViewController: UIViewController, UITextFieldDelegate {
    
      @IBOutlet weak var txtFieldName: UITextField!
      @IBOutlet weak var txtFieldEmail: UITextField!
      @IBOutlet weak var txtFieldPassword: UITextField!
    
      override func viewDidLoad() {
        super.viewDidLoad()
    
      }
    
      //MARK: - Controlling the Keyboard
      func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    
        if textField == txtFieldName {
           textField.resignFirstResponder()
           txtFieldEmail.becomeFirstResponder()
        } else if textField == txtFieldEmail {
           textField.resignFirstResponder()
           txtFieldPassword.becomeFirstResponder()
        } else if textField == txtFieldPassword {
           textField.resignFirstResponder()
        }
       return true
      }
    }
    
13
Vinoth Vino

Je suggère que vous devriez utiliser l'instruction switch dans textFieldShouldReturn(_:).

// MARK: UITextFieldDelegate

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    switch textField {
    case nameTextField:
        phoneTextField.becomeFirstResponder()
    case phoneTextField:
        emailTextField.becomeFirstResponder()
    case emailTextField:
        descriptionTextField.becomeFirstResponder()
    default:
        textField.resignFirstResponder()
    }
    return false
}
11
kubacizek

Cette approche nécessite quelques modifications dans les vues de table et de collection, mais je suppose qu'elle convient aux formulaires simples.

Connectez votre textFields à une IBOutletCollection, triez-la par sa coordonnée y et dans textFieldShouldReturn(_:), passez au champ de texte suivant jusqu'à la fin:

@IBOutlet var textFields: [UITextField]!

...

textFields.sortInPlace { $0.frame.Origin.y < $1.frame.Origin.y }

...

func textFieldShouldReturn(textField: UITextField) -> Bool {
    if let currentIndex = textFields.indexOf(textField) where currentIndex < textFields.count-1 {
        textFields[currentIndex+1].becomeFirstResponder()
    } else {
        textField.resignFirstResponder()
    }
    return true
}    

Ou regardez simplement exemple de projet (xcode 7 beta 4)

7
libec

J'ai essayé de nombreux codes et cela a finalement fonctionné pour moi dans Swift 3.0 Latest [March 2017]

La classe "ViewController" doit hériter de "UITextFieldDelegate" pour que ce code fonctionne.

class ViewController: UIViewController,UITextFieldDelegate  

Ajoutez le champ de texte avec le numéro de balise approprié et ce numéro de balise est utilisé pour amener le contrôle au champ de texte approprié en fonction du numéro de balise incrémentiel qui lui est attribué.

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 code "returnKeyType = UIReturnKeyType.next" où la touche de retour du clavier à afficher en tant que "Suivant" comporte également d'autres options telles que "Rejoindre/Aller", etc., en fonction des modifications apportées par votre application.

Ce "textFieldShouldReturn" est une méthode contrôlée par UITextFieldDelegate et nous avons ici la sélection de champ suivante basée sur l'incrémentation de la valeur de la balise

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

    }
4

le moyen le plus simple de passer au champ de texte suivant est-il inutile d'utiliser un code long 

override func viewDidLoad() {
        super.viewDidLoad()

        emailTextField.delegate = self
        passwordTextField.delegate = self
    }


    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField == emailTextField {
            passwordTextField.becomeFirstResponder()
        }else {
            passwordTextField.resignFirstResponder()
        }
            return true
    }
3
mazenqp

Caleb's version in Swift 4.0

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if let nextField = self.view.viewWithTag(textField.tag + 1) as? UITextField {
        nextField.becomeFirstResponder()
    } else {
        textField.resignFirstResponder()
    }
    return false
}

P.S. textField.superview? ne fonctionne pas pour moi

2
coldembrace

Swift 4.2

Ceci est une Plus générique et plus facile Solution, vous pouvez utiliser ce code avec n’importe quelle quantité de TextFields. Il suffit d'hériter UITextFieldDelegate et de mettre à jour la balise Textfield selon l'ordre et de copier cette fonction

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    let txtTag:Int = textField.tag

    if let textFieldNxt = self.view.viewWithTag(txtTag+1) as? UITextField {
        textFieldNxt.becomeFirstResponder()
    }else{
        textField.resignFirstResponder()
    }

    return true
}
2
Lahiru Pinto

Utilisez simplement la méthode becomeFirstResponder() de la classe UIResponder dans votre méthode textFieldShouldReturn. Tous les objets UIView sont des sous-classes de UIResponder.

if self.emaillabel.isEqual(self.anotherTextField)
{
    self.anotherTextField.becomeFirstResponder()
}

Vous pouvez trouver plus d’informations sur la méthode becomeFirstResponder() chez Apple Doc dans ici .

2
Candost Dagdeviren

Swift/Programmatically

class MyViewController: UIViewController, UITextFieldDelegate {

    let textFieldA = UITextField()
    let textFieldB = UITextField()
    let textFieldC = UITextField()
    let textFieldD = UITextField()

    var textFields: [UITextField] {
        return [textFieldA, textFieldB, textFieldC, textFieldD]
    }

    override func viewDidLoad() {
        // layout textfields somewhere 
        // then set delegate
        textFields.forEach { $0.delegate = self }
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if let selectedTextFieldIndex = textFields.firstIndex(of: textField), selectedTextFieldIndex < textFields.count - 1 {
            textFields[selectedTextFieldIndex + 1].becomeFirstResponder()
        } else {
            view.endEditing(true) // last textfield, dismiss keyboard directly
        }
        return true
    }
}
1
T. Wei

Une méthode alternative pour les puristes qui n'aiment pas utiliser les balises et qui souhaite que le délégué UITextField soit la cellule permettant de garder les composants séparés ou unidirectionnels ...

  1. Créez un nouveau protocole pour lier les cellules et le TableViewController.

    protocol CellResponder {
      func setNextResponder(_ fromCell: UITableViewCell)
    }
    
  2. Ajoutez le protocole à votre cellule, où votre délégué TextField est également la cellule (je le fais dans le Storyboard).

    class MyTableViewCell: UITableViewCell, UITextFieldDelegate {
      var responder: CellResponder?
    
      func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        responder?.setNextResponder(self)
        return true
      }
    }
    
  3. Assurez-vous que votre TableViewController est conforme au protocole CellResponder (c'est-à-dire class MyTableViewController: UITableViewController, CellResponder) et implémentez la méthode à votre guise. C'est à dire. Si vous avez différents types de cellules, vous pouvez le faire, vous pouvez également passer dans IndexPath, utiliser une balise, etc. N'oubliez pas de définir cell.responder = self dans cellForRow ..

    func setNextResponder(_ fromCell: UITableViewCell) {
      if fromCell is MyTableViewCell, let nextCell = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? MySecondTableViewCell {
    
        nextCell.aTextField?.becomeFirstResponder()
    
      } ....
    }
    
1
mm282

Si vous avez beaucoup de composants de champs de texte, il pourrait être préférable d’utiliser une collection de sorties, de lier des champs de texte et de définir la clé de retour depuis le constructeur d’interface 

@IBOutlet var formTextFields: [UITextField]!

override func viewDidLoad() {
  for textField in formTextFields {
    textField.delegate = self
  }
}

extension RegisterViewController: UITextFieldDelegate {
  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if let componentIndex = formTextFields.firstIndex(of: textField) {
      if textField.returnKeyType == .next,
        componentIndex < (formTextFields.count - 1) {
        formTextFields[componentIndex + 1].becomeFirstResponder()
      } else {
        textField.resignFirstResponder()
      }
    }
    return true
  }
}
0
antonio.reyes

Aucune spéciale, voici mon utilisation actuelle pour changer le champ de texte. Donc, le code dans ViewController a l'air bien :). # Swift4 

final class SomeTextFiled: UITextField {

  public var actionKeyboardReturn: (() -> ())?

  override init(frame: CGRect) {
      super.init(frame: frame)
      super.delegate = self
  }

  required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
      fatalError("init(coder:) has not been implemented")
  }

  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
      self.resignFirstResponder()
      actionKeyboardReturn?()
      return true
   }
}

extension SomeTextFiled: UITextFieldDelegate {}


class MyViewController : UIViewController {

    var tfName: SomeTextFiled!
    var tfEmail: SomeTextFiled!
    var tfPassword: SomeTextFiled!

    override func viewDidLoad() {
        super.viewDidLoad()
        tfName = SomeTextFiled(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        tfName.actionKeyboardReturn = { [weak self] in
            self?.tfEmail.becomeFirstResponder()
        }
        tfEmail = SomeTextFiled(frame: CGRect(x: 100, y: 0, width: 100, height: 100))
        tfEmail.actionKeyboardReturn = { [weak self] in
            self?.tfPassword.becomeFirstResponder()
        }
        tfPassword = SomeTextFiled(frame: CGRect(x: 200, y: 0, width: 100, height: 100))
        tfPassword.actionKeyboardReturn = {
            /// Do some further code
        }
    }
}
0
Stephen Chen

J'ai une bonne solution à votre question.

STEP:

1 - Définissez votre clé de retour à partir du storyboard.

 enter image description here 

2 - Dans votre dossier Swift.

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField.returnKeyType == .next {
            Email.resignFirstResponder()
            Password.becomeFirstResponder()
        } else if textField.returnKeyType == .go {
            Password.resignFirstResponder()
            self.Login_Action()
        }
        return true
    }

3 - N'oubliez pas de définir le délégué du champ de texte.

Je vous remercie :)

0
Parth Patel