Wie überprüfe ich, wann sich ein UITextField ändert?


290

Ich versuche zu überprüfen, wann sich ein Textfeld ändert, was auch der für textView verwendeten Funktion entspricht. textViewDidChangeBisher habe ich Folgendes getan:

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

Welche Art von funktioniert, aber das topRightButtonist aktiviert, sobald das Textfeld gedrückt wird. Ich möchte, dass es nur aktiviert wird, wenn tatsächlich Text eingegeben wird?

Antworten:


739

SCHNELL

Swift 4.2

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

und

@objc func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 3 & Swift 4.1

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

und

func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 2.2

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

und

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

ZIEL C

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

und textFieldDidChange-Methode ist

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

Das stürzt für mich ab und ich verstehe nicht warum.
Levi Roberts

1
Mehrfach überprüft. Der Delegat wird unmittelbar davor festgelegt viewDidLoad. Die Aktion ist Buchstabe für Buchstabe gleich. Die App stürzt ab, sobald eine Tastaturtaste gedrückt wird. Edit: Hab es herausgefunden! Es fehlte das Semikolon in der Aktion. Ich nahm an, dass es nur mit dem Funktionsnamen identisch sein musste.
Levi Roberts

@FawadMasud dies macht jetzt nichts in Swift 2.0 auf iOS 9 mit XCode 7 wurde es abgeschrieben oder kennen Sie die aktuelle Möglichkeit, es zu beheben?
Cody Weaver

1
@bibscy Ja, Sie müssen alle Textfelder in einer Ansicht durchlaufen.
Fawad Masud

1
Für Swift 4.2 ist es: Texttfield.addTarget (self, action: #selector (ViewControllerr.textFieldDidChange (_ :)), für: UIControl.Event.editingChanged)
Beenden Sie den

128

Sie können diese Verbindung im Interface Builder herstellen.

  1. Klicken Sie in Ihrem Storyboard oben auf dem Bildschirm auf den Assistenten-Editor (zwei Kreise in der Mitte). Assistent Editor ausgewählt

  2. Strg + Klicken Sie im Interface Builder auf das Textfeld.

  3. Ziehen Sie von EditingChanged in Ihre Ansichtssteuerungsklasse in der Assistentenansicht. Verbindung herstellen

  4. Benennen Sie Ihre Funktion (z. B. "textDidChange") und klicken Sie auf Verbinden. Namensfunktion


3
Dies ist eine großartige Lösung, insbesondere wenn es sich um ein UITextField in einer tableViewCell handelt, die von einer separaten Datenquelle verwaltet wird. Dieser Ansatz ermöglicht es dem viewController, direkt zu antworten (daher muss die Datenquelle nicht antworten und die Aktion delegieren).
Wuf810

1
Großartig - eine einfache Lösung für ein irritierendes Problem. Sie können natürlich mehrere Textfelder verknüpfen
Jeremy Andrews

1
Wahrscheinlich eine bessere Antwort als oben, da der Zusatz @objc func eliminiert wird.
Matthew Bradshaw

Gute Idee, ich benutze Event DidEndEditing
Puji Wahono

Dies ist die beste Lösung. Danke @rmooney!
Jonathan

63

Swift 5.0

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

und Handle-Methode:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 4.0

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

und Handle-Methode:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 3.0

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

und Handle-Methode:

func textFieldDidChange(textField: UITextField) { 

}

29

So habe ich es bisher gemacht: in 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
}

Swift4-Version

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
Dies wird nicht aufgerufen, wenn ein Textfeld leer ist und der Benutzer auf die Rücktaste klickt.
Matthew Mitchell

14

Swift 3

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

7

Swift 3.0.1+ (Einige der anderen Swift 3.0-Antworten sind nicht aktuell)

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

func textFieldDidChange(_ textField: UITextField) {

}

6

textField (_: shouldChangeCharactersIn: replaceString :) hat in Xcode 8, Swift 3 für mich funktioniert, wenn Sie jeden einzelnen Tastendruck überprüfen möchten.

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

Konform mit 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

Sie können diese Delegatmethode aus UITextFieldDelegate verwenden. Es wird bei jeder Charakteränderung ausgelöst.

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

Doch diese wird nur ausgelöst , BEVOR eine Änderung vorgenommen wird (in der Tat wird eine Änderung nur gemacht , wenn Sie von hier wahr tun zurück).


1
Wie soll das geschrieben werden, da ich auch diese Methode ausprobiert habe und zu derselben Lösung komme, bei der sie sich nur ändert, wenn das textField aktiviert ist, nicht, wenn sich der Text tatsächlich ändert?

Wenn Sie die oben genannte Delegatenmethode implementieren, wird sie jedes Mal ausgelöst, wenn Sie Ihren Text ändern. Sie müssen nur diesen Code hinzufügen, self.textfield.delegate = self
Abubakr Dar

Bei mir hat diese Methode nicht funktioniert, da Sie nicht überprüfen konnten, ob das Textfeld in der Methode leer war. In erster Linie, weil es wahr / falsch zurückgibt, je nachdem, ob sich das Textfeld ändern kann. Das Ereignis wird ausgelöst, BEVOR das Textfeld die Möglichkeit hatte, leer zu werden.
Levi Roberts

@ LeviRoberts, Sie haben einen Verweis auf ein Textfeld innerhalb dieser Methode. So können Sie überprüfen, ob die Datei textfield.text leer ist.
Abubakr Dar

Sie scheinen nicht zu verstehen. Wenn es leer ist, entspricht die .isEmptyMethode erst dann true, wenn diese Methode die Chance hatte, true zurückzugeben. um der App mitzuteilen, dass sich das Textfeld ändern soll.
Levi Roberts

3

Vielleicht RxSwift verwenden?

brauchen

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

Importe offensichtlich hinzufügen

import RxSwift
import RxCocoa

Also hast du eine textfield : UITextField

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

Du hast andere 3 Methoden ..

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

Um nur Ereignisse mit echten Änderungen zu erhalten und nicht auch, als das Textfeld zum Ersthelfer wurde, müssen Sie differentUntilChanged für Text verwenden.
RealNmae

1

Swift 4

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

@objc func textIsChanging(_ textField:UITextField) {

 print ("TextField is changing")

}

Wenn Sie eine Änderung vornehmen möchten, nachdem der Benutzer vollständig eingegeben hat (wird aufgerufen, sobald der Benutzer die Tastatur schließt oder die Eingabetaste drückt).

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

Sie sollten diese Schritte ausführen:

  1. Machen Sie einen Outlet-Verweis auf das Textfeld
  2. Weisen Sie der Controller-Klasse UITextFieldDelegate zu
  3. Konfigurieren Sie yourTextField.delegate
  4. Implementieren Sie die gewünschte Funktion

Beispielcode:

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

So können Sie textField text change listenermit Swift 3 ein hinzufügen :

Erklären Sie Ihre Klasse als UITextFieldDelegate

override func viewDidLoad() {
    super.viewDidLoad()

    textField.delegate = self

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

Fügen Sie dann traditionell eine textFieldShouldEndEditing-Funktion hinzu:

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

0

Swift 4.2

Schreiben Sie dies in viewDidLoad

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

Schreiben Sie diese außerhalb von viewDidLoad

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

Sie können das Ereignis durch UIControl.Event.editingDidBegin oder was auch immer Sie erkennen möchten, ändern.


0

Nur für den Fall, dass Sie an einer SwiftUI-Lösung interessiert sind, funktioniert dies für mich:

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

Ich muss sagen, es ist nicht meine Idee, ich habe es in diesem Blog gelesen: SwiftUI-Bindung: Ein sehr einfacher Trick


0

Falls es nicht möglich ist, das addTarget an Ihr UITextField zu binden, empfehle ich Ihnen, eines davon wie oben vorgeschlagen zu binden und den Code für die Ausführung am Ende der shouldChangeCharactersIn-Methode einzufügen.

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

Und beim Aufruf in 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

schnell 4

In 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

Fügen Sie diese Funktion hinzu:

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

-1

Erstellen Sie eine neue benutzerdefinierte Klasse 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
}

}

Bei allem Respekt ist dies eine schreckliche Lösung. Er möchte nur überprüfen, ob a UITextFieldseinen Wert aktualisiert hat - warum eine übermäßig komplexe Klasse erstellen, um dieses einfache Problem zu lösen?
Guilherme Matuella

@ GuilhermeMatuella Dies ist mehr zum Front-End-Code, damit der Benutzer weiß, ob das Feld erforderlich und ausgefüllt ist. Es ist ein anderer Ansatz, um das gleiche Problem zu lösen. Dies ist im Grunde mein benutzerdefiniertes Vermögen
Muhammad Asyraf
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.