Como verifico quando um UITextField é alterado?


290

Estou tentando verificar quando um campo de texto é alterado, equivalente também à função usada para textView - textViewDidChangeaté agora, fiz isso:

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

Que tipo de trabalho, mas topRightButtonestá ativado assim que o campo de texto é pressionado, desejo que seja ativado apenas quando o texto é realmente digitado?

Respostas:


739

RÁPIDO

Swift 4.2

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

e

@objc func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 3 e Swift 4.1

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

e

func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 2.2

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

e

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

OBJETIVO-C

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

e o método textFieldDidChange é

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

Isso trava para mim e eu não entendo o porquê.
Levi Roberts

1
Verificado várias vezes. O delegado é definido imediatamente antes dele viewDidLoad. A ação é letra por letra da mesma forma. O aplicativo falha assim que um botão do teclado é pressionado. Edit: Descobri isso! Faltava o ponto e vírgula dentro da ação. Eu supus que só tinha que ser o mesmo que o nome da função.
Levi Roberts

@FawadMasud isso não faz nada agora no Swift 2.0 no iOS 9 com XCode 7, foi depreciado ou você conhece a maneira atual de corrigi-lo?
Cody Weaver

1
@ bibscy sim, você precisa percorrer todos os campos de texto dentro de uma visualização.
Fawad Masud

1
Para o Swift 4.2: Texttfield.addTarget (self, action: #selector (ViewControllerr.textFieldDidChange (_ :)), para: UIControl.Event.editingChanged)
Saia de

128

Você pode fazer essa conexão no construtor de interface.

  1. No seu storyboard, clique no editor assistente na parte superior da tela (dois círculos no meio). Editor assistente selecionado

  2. Ctrl + Clique no campo de texto no construtor de interfaces.

  3. Arraste de EditingChanged para dentro da classe do controlador de exibição na exibição do assistente. Fazendo conexão

  4. Nomeie sua função ("textDidChange", por exemplo) e clique em conectar. Função de nomeação


3
Essa é uma ótima solução, especialmente se estiver lidando com um UITextField em um tableViewCell que está sendo gerenciado por uma fonte de dados separada. Essa abordagem permite que o viewController responda diretamente (portanto, a fonte de dados não precisa responder e delegar a ação).
Wf810

1
Ótimo - uma solução simples para um problema irritante. Obviamente, você pode vincular vários campos de texto
Jeremy Andrews

1
Provavelmente, uma resposta melhor que a anterior, porque a eliminação da adição de @objc func.
Matthew Bradshaw

Boa idéia, eu uso o evento DidEndEditing
Puji Wahono

essa é a melhor solução. Obrigado @rmooney!
Jonathan

63

Swift 5.0

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

e manipular método:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 4.0

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

e manipular método:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 3.0

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

e manipular método:

func textFieldDidChange(textField: UITextField) { 

}

29

A maneira como eu lidei com isso até agora: em 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
}

Versão 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
Isso não será chamado quando um campo de texto estiver vazio e o usuário clicar em backspace.
Matthew Mitchell

14

Swift 3

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

7

Swift 3.0.1+ (Algumas das outras respostas do Swift 3.0 não estão atualizadas)

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

func textFieldDidChange(_ textField: UITextField) {

}

6

O textField (_: shouldChangeCharactersIn: ReplacementString :) funcionou para mim no Xcode 8, Swift 3, se você quiser verificar cada pressionamento de tecla.

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

Conformidade com 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

Você pode usar este método delegado de UITextFieldDelegate. É acionado a cada mudança de personagem.

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

No entanto, isso só acontece antes que uma alteração seja feita (na verdade, uma alteração é feita apenas se você retornar verdadeiro a partir daqui).


1
Como isso deve ser escrito, como eu também tentei esse método e chegue à mesma solução, onde ele muda apenas quando o textField é ativado, e não quando o texto realmente muda?

Quando você implementa o método delegado acima, ele é acionado toda vez que você altera seu texto. Você só precisa adicionar este código, self.textfield.delegate = self
Abubakr Dar

Para mim, esse método não funcionou porque você não pôde verificar se o campo de texto estava vazio dentro do método. Principalmente porque retorna verdadeiro / falso, dependendo se o campo de texto puder mudar. Portanto, o evento é acionado ANTES do campo de texto ter tido a chance de ficar vazio.
Levi Roberts

@LeviRoberts, você tem uma referência ao campo de texto dentro deste método. Assim, você pode verificar se o campo de texto. Texto está vazio.
Abubakr Dar

Você parece não entender. Quando está vazio, o .isEmptymétodo não equivale a verdadeiro até que APÓS este método tenha tido a chance de retornar verdadeiro; para informar ao aplicativo que o campo de texto deve mudar.
Levi Roberts

3

Talvez use RxSwift?

necessidade

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

adicionar importações obviamente

import RxSwift
import RxCocoa

Então você tem um textfield : UITextField

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

Você tem outros 3 métodos ..

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

Para receber apenas eventos de mudança real e não também quando o campo de texto se tornou o primeiro respondedor, é necessário usar oUnitUnChanged no texto.
RealNmae 10/11/19

1

Swift 4

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

@objc func textIsChanging(_ textField:UITextField) {

 print ("TextField is changing")

}

Se você quiser fazer uma alteração depois que o usuário digitar completamente (será chamado assim que o usuário desconectar o teclado ou pressionar enter).

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

Você deve seguir estas etapas:

  1. Faça uma referência de saída para o campo de texto
  2. AssignUITextFieldDelegate à classe do controlador
  3. Configure yourTextField.delegate
  4. Implemente qualquer função que você precise

Código de amostra:

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

É assim que você pode adicionar um Swift 3textField text change listener usando :

Declare sua classe como UITextFieldDelegate

override func viewDidLoad() {
    super.viewDidLoad()

    textField.delegate = self

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

Em seguida, basta adicionar tradicionalmente uma função textFieldShouldEndEditing:

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

0

Swift 4.2

escreva isso em viewDidLoad

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

escreva isso fora viewDidLoad

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

Você pode alterar o evento usando UIControl.Event.editingDidBegin ou o que você quiser detectar.


0

Caso você esteja interessado em uma solução SwiftUI, isso está funcionando para mim:

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

Eu tenho que dizer que não é minha ideia, eu li neste blog: SwiftUI binding: Um truque muito simples


0

Caso não seja possível vincular o addTarget ao seu UITextField, aconselho a vincular um deles, conforme sugerido acima, e insira o código para execução no final do método 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
    }
}

E na chamada 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

veloz 4

Em 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

Adicione esta função:

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

-1

crie uma nova classe personalizada 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
}

}

Com todo o respeito, esta é uma solução horrível. Ele só quer verificar se a UITextFieldatualizou seu valor - por que criar uma classe muito complexa para resolver esse problema simples?
Guilherme Matuella

@GuilhermeMatuella, este é mais um código de front-end para que o usuário saiba se o campo é obrigatório e preenchido. é uma abordagem diferente para resolver o mesmo problema. este é basicamente meus ativos personalizados
Muhammad Asyraf
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.