Comment vérifier quand un UITextField change?


290

J'essaie de vérifier quand un champ de texte change, équivalent aussi à la fonction utilisée pour textView - textViewDidChangejusqu'à présent, je l'ai fait:

  func textFieldDidBeginEditing(textField: UITextField) {
        if self.status.text == "" && self.username.text == "" {
            self.topRightButton.enabled = false
        } else {   
            self.topRightButton.enabled = true
        }
    }

Quel type de travaux, mais topRightButtonest activé dès que le champ de texte est activé, je veux qu'il ne soit activé que lorsque le texte est réellement tapé?

Réponses:


739

RAPIDE

Swift 4.2

textfield.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)

et

@objc func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 3 et swift 4.1

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)

et

func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 2.2

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), forControlEvents: UIControlEvents.EditingChanged)

et

func textFieldDidChange(textField: UITextField) {
    //your code
}

OBJECTIF C

[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

et la méthode textFieldDidChange est

-(void)textFieldDidChange :(UITextField *) textField{
    //your code
}

Cela se bloque pour moi et je ne comprends pas pourquoi.
Levi Roberts

1
Vérifié plusieurs fois. Le délégué est placé juste avant lui à l'intérieur viewDidLoad. L'action est la même pour chaque lettre. L'application se bloque dès qu'un bouton du clavier est enfoncé. Edit: Compris! Il manquait le point-virgule à l'intérieur de l'action. J'ai supposé que cela ne devait être que le nom de la fonction.
Levi Roberts

@FawadMasud cela ne fait rien maintenant dans Swift 2.0 sur iOS 9 avec XCode 7 a-t-il été déprécié ou connaissez-vous la façon actuelle de le réparer?
Cody Weaver

1
@bibscy oui, vous devez parcourir tous les champs de texte dans une vue.
Fawad Masud

1
Pour Swift 4.2 c'est: Texttfield.addTarget (auto, action: #selector (ViewControllerr.textFieldDidChange (_ :)), pour: UIControl.Event.editingChanged)
Quittez le

128

Vous pouvez établir cette connexion dans le générateur d'interface.

  1. Dans votre storyboard, cliquez sur l'éditeur assistant en haut de l'écran (deux cercles au milieu). Éditeur adjoint sélectionné

  2. Ctrl + clic sur le champ de texte dans le générateur d'interface.

  3. Faites glisser de EditingChanged vers l'intérieur de votre classe de contrôleur de vue dans la vue de l'assistant. Établir une connexion

  4. Nommez votre fonction ("textDidChange" par exemple) et cliquez sur se connecter. Fonction de dénomination


3
C'est une excellente solution, surtout si vous traitez un UITextField dans une tableViewCell qui est gérée par une source de données distincte. Cette approche permet au viewController de répondre directement (ainsi la source de données n'a pas à répondre et déléguer l'action).
wuf810

1
Génial - une solution simple à un problème irritant. Vous pouvez bien sûr lier plusieurs champs de texte
Jeremy Andrews

1
Probablement une meilleure réponse que ci-dessus car l'élimination de l'addition @objc func.
Matthew Bradshaw

Good Idea, I use event DidEndEditing
Puji Wahono

C'est la meilleure solution. Merci @rmooney!
Jonathan

63

Swift 5.0

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
                          for: .editingChanged)

et gérer la méthode:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 4.0

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
                          for: UIControlEvents.editingChanged)

et gérer la méthode:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 3.0

textField.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: .editingChanged)

et gérer la méthode:

func textFieldDidChange(textField: UITextField) { 

}

29

La façon dont je l'ai géré jusqu'à présent: dans UITextFieldDelegate

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
    // text hasn't changed yet, you have to compute the text AFTER the edit yourself
    let updatedString = (textField.text as NSString?)?.stringByReplacingCharactersInRange(range, withString: string)

    // do whatever you need with this updated string (your code)


    // always return true so that changes propagate
    return true
}

Version Swift4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
    return true
}

1
Cela ne sera pas appelé lorsqu'un champ de texte est vide et que l'utilisateur clique sur retour arrière.
Matthew Mitchell

14

Swift 3

 textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(sender:)), for: UIControlEvents.editingChanged)

7

Swift 3.0.1+ (certaines des autres réponses de swift 3.0 ne sont pas à jour)

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
                          for: UIControlEvents.editingChanged)

func textFieldDidChange(_ textField: UITextField) {

}

6

textField (_: shouldChangeCharactersIn: replacementString :) a fonctionné pour moi dans Xcode 8, Swift 3 si vous voulez vérifier chaque pression de touche.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    // Whatever code you want to run here.
    // Keep in mind that the textfield hasn't yet been updated,
    // so use 'string' instead of 'textField.text' if you want to
    // access the string the textfield will have after a user presses a key

    var statusText = self.status.text
    var usernameText = self.username.text

    switch textField{
    case self.status:
        statusText = string
    case self.username:
        usernameText = string
    default:
        break
    }

    if statusText == "" && usernameText == "" {
        self.topRightButton.enabled = false
    } else {   
        self.topRightButton.enabled = true
    }

    //Return false if you don't want the textfield to be updated
    return true
}

5

Swift 4

Conforme à UITextFieldDelegate .

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // figure out what the new string will be after the pending edit
    let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)

    // Do whatever you want here


    // Return true so that the change happens
    return true
}

4

Vous pouvez utiliser cette méthode déléguée depuis UITextFieldDelegate. Il se déclenche à chaque changement de personnage.

(Objective C) textField:shouldChangeCharactersInRange:replacementString:
(Swift) textField(_:shouldChangeCharactersInRange:replacementString:)

Cependant, ceci ne se déclenche qu'avant qu'un changement soit effectué (en effet, un changement n'est effectué que si vous revenez vrai d'ici).


1
Comment cela devrait-il être écrit car j'ai également essayé cette méthode et j'arrive à la même solution où elle ne change qu'une fois que le textField est activé, pas une fois que le texte change réellement ??

Lorsque vous implémentez la méthode déléguée ci-dessus, elle se déclenche chaque fois que vous modifiez votre texte. Il vous suffit d'ajouter ce code, self.textfield.delegate = self
Abubakr Dar

Pour moi, cette méthode n'a pas fonctionné car vous ne pouviez pas vérifier si le champ de texte était vide à l'intérieur de la méthode. Principalement parce qu'il retourne vrai / faux selon SI le champ de texte peut changer. L'événement se déclenche donc AVANT que le champ de texte n'ait pu se vider.
Levi Roberts

@LeviRoberts, Vous avez une référence au champ de texte à l'intérieur de cette méthode. Vous pouvez donc vérifier si le textfield.text est vide.
Abubakr Dar

Vous ne semblez pas comprendre. Lorsqu'elle est vide, la .isEmptyméthode n'est pas équivalente à true tant qu'APRÈS que cette méthode n'a pas eu la chance de retourner true; pour indiquer à l'application que le champ de texte doit changer.
Levi Roberts

3

Peut-être utiliser RxSwift?

avoir besoin

pod 'RxSwift',    '~> 3.0'
pod 'RxCocoa',    '~> 3.0'

ajouter des importations évidemment

import RxSwift
import RxCocoa

Alors tu as un textfield : UITextField

let observable: Observable<String?> = textField.rx.text.asObservable()
observable.subscribe(
            onNext: {(string: String?) in
                print(string!)
        })

Vous avez 3 autres méthodes ..

  1. onError
  2. onCompleted
  3. onDisposed
  4. onNext

Pour recevoir des événements de changement réel uniquement et pas également lorsque textfield est devenu premier intervenant, vous devez utiliser distinctUntilChanged sur du texte.
RealNmae

1

Swift 4

textField.addTarget(self, action: #selector(textIsChanging), for: UIControlEvents.editingChanged)

@objc func textIsChanging(_ textField:UITextField) {

 print ("TextField is changing")

}

Si vous souhaitez effectuer une modification une fois que l'utilisateur a tapé complètement (il sera appelé une fois que l'utilisateur aura fermé le clavier ou appuyé sur Entrée).

textField.addTarget(self, action: #selector(textDidChange), for: UIControlEvents.editingDidEnd)

 @objc func textDidChange(_ textField:UITextField) {

       print ("TextField did changed") 
 }

1
txf_Subject.addTarget(self, action:#selector(didChangeFirstText), for: .editingChanged)

@objc func didChangeText(textField:UITextField) {
    let str = textField.text
    if(str?.contains(" "))!{
        let newstr = str?.replacingOccurrences(of: " ", with: "")
        textField.text = newstr
    }
}

@objc func didChangeFirstText(textField:UITextField) {
    if(textField.text == " "){
        textField.text = ""
    }
}

1

Vous devez suivre ces étapes:

  1. Faire une référence de sortie au champ de texte
  2. AssignUITextFieldDelegate à la classe de contrôleur
  3. Configurez votreTextField.delegate
  4. Implémentez la fonction dont vous avez besoin

Exemple de code:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var yourTextFiled : UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        yourTextFiled.delegate = self
    }


    func textFieldDidEndEditing(_ textField: UITextField) {
        // your code
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        // your code
    }

    .
    .
    .
}

0

Voici comment vous pouvez ajouter une textField text change listeneraide de Swift 3 :

Déclarez votre classe comme UITextFieldDelegate

override func viewDidLoad() {
    super.viewDidLoad()

    textField.delegate = self

    textField.addTarget(self, action: #selector(UITextFieldDelegate.textFieldShouldEndEditing(_:)), for: UIControlEvents.editingChanged)
}

Ensuite, ajoutez simplement une fonction textFieldShouldEndEditing:

func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { // do stuff
        return true 
}

0

Swift 4.2

écrire ceci dans viewDidLoad

// to detect if TextField changed
TextField.addTarget(self, action: #selector(textFieldDidChange(_:)),
                                   for: UIControl.Event.editingChanged)

écrire cette vue extérieureDidLoad

@objc func textFieldDidChange(_ textField: UITextField) {
    // do something
}

Vous pouvez modifier l'événement par UIControl.Event.editingDidBegin ou tout ce que vous souhaitez détecter.


0

Au cas où vous seriez intéressé par une solution SwiftUI, celle-ci fonctionne pour moi:

 TextField("write your answer here...",
            text: Binding(
                     get: {
                        return self.query
                       },
                     set: { (newValue) in
                        self.fetch(query: newValue) // any action you need
                                return self.query = newValue
                      }
            )
  )

Je dois dire que ce n'est pas mon idée, je l'ai lu dans ce blog: Reliure SwiftUI: une astuce très simple


0

Dans le cas où il n'est pas possible de lier l'addTarget à votre UITextField, je vous conseille de lier l'un d'eux comme suggéré ci-dessus et d'insérer le code pour exécution à la fin de la méthode shouldChangeCharactersIn.

nameTextField.addTarget(self, action: #selector(RegistrationViewController.textFieldDidChange(_:)), for: .editingChanged)

@objc func textFieldDidChange(_ textField: UITextField) {
    if phoneNumberTextField.text!.count == 17 && nameTextField.text!.count > 0 {
        continueButtonOutlet.backgroundColor = UIColor(.green)
    } else {
        continueButtonOutlet.backgroundColor = .systemGray
    }
}

Et en appel dans shouldChangeCharactersIn func.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    guard let text = textField.text else {
        return true
    }
    let lastText = (text as NSString).replacingCharacters(in: range, with: string) as String

    if phoneNumberTextField == textField {
        textField.text = lastText.format("+7(NNN)-NNN-NN-NN", oldString: text)
        textFieldDidChange(phoneNumberTextField)
        return false
    }
    return true
}

-1

rapide 4

Dans viewDidLoad ():

    //ADD BUTTON TO DISMISS KEYBOARD

    // Init a keyboard toolbar 
    let toolbar = UIView(frame: CGRect(x: 0, y: view.frame.size.height+44, width: view.frame.size.width, height: 44))
    toolbar.backgroundColor = UIColor.clear

    // Add done button
    let doneButt = UIButton(frame: CGRect(x: toolbar.frame.size.width - 60, y: 0, width: 44, height: 44))
    doneButt.setTitle("Done", for: .normal)
    doneButt.setTitleColor(MAIN_COLOR, for: .normal)
    doneButt.titleLabel?.font = UIFont(name: "Titillium-Semibold", size: 13)
    doneButt.addTarget(self, action: #selector(dismissKeyboard), for: .touchUpInside)
    toolbar.addSubview(doneButt)

    USDTextField.inputAccessoryView = toolbar

Ajoutez cette fonction:

    @objc func dismissKeyboard() {
      //Causes the view (or one of its embedded text fields) to resign the first responder status.
      view.endEditing(true)
    }

-1

créer une nouvelle classe personnalisée MaterialTextfield.swift

class MaterialTextfield: UITextField,UITextFieldDelegate {

var bottomBorder = UIView()
var shouldShowEditing = false

override func awakeFromNib() {

    // Setup Bottom-Border

    self.delegate = self
    self.translatesAutoresizingMaskIntoConstraints = false

    bottomBorder = UIView.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
    bottomBorder.backgroundColor = UIColor(rgb: 0xE2DCD1) // Set Border-Color
    bottomBorder.translatesAutoresizingMaskIntoConstraints = false

    addSubview(bottomBorder)

    bottomBorder.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    bottomBorder.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
    bottomBorder.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
    bottomBorder.heightAnchor.constraint(equalToConstant: 1).isActive = true // Set Border-Strength

}
@IBInspectable var hasError: Bool = false {
    didSet {
        if (hasError) {
            bottomBorder.backgroundColor = UIColor.red//error color
        } else {
            bottomBorder.backgroundColor = UIColor(rgb: 0xE2DCD1)//passive color
        }

    }
}
@IBInspectable var showEditing: Bool = false{
    didSet {
        if (showEditing) {
            bottomBorder.backgroundColor = UIColor(rgb: 0x56B5CA)//active color
        } else {
            bottomBorder.backgroundColor = UIColor(rgb: 0xE2DCD1)//passive color
        }

    }

}

func textFieldDidBeginEditing(_ textField: UITextField) {//listen to on edit event
    showEditing = !self.showEditing
}
func textFieldDidEndEditing(_ textField: UITextField) {//listen to on end edit event
    showEditing = !self.showEditing
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {//listen to return button event
    textField.resignFirstResponder() // return button will close keyboard
    return true
}

}

Avec tout le respect que je vous dois, c'est une solution horrible. Il veut juste vérifier si a UITextFielda mis à jour sa valeur - pourquoi créer une classe trop complexe pour résoudre ce problème simple?
Guilherme Matuella

@GuilhermeMatuella c'est plus du code frontal pour que l'utilisateur sache si le champ est requis et rempli. c'est une approche différente pour résoudre le même problème. c'est essentiellement mes atouts personnalisés
Muhammad Asyraf
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.