Evento de cambio de texto UITextField


¿Cómo puedo detectar cualquier cambio de texto en un campo de texto? El método delegado shouldChangeCharactersInRange funciona para algo, pero no satisfizo exactamente mi necesidad. Dado que hasta que devuelve SÍ, los textos TextField no están disponibles para otros métodos observadores.

Por ejemplo, en mi código calculateAndUpdateTextFields no recibió el texto actualizado, el usuario ha escrito.

Es su forma de obtener algo como textChanged Controlador de eventos Java.

- (BOOL)textField:(UITextField *)textField 
            shouldChangeCharactersInRange:(NSRange)range 
            replacementString:(NSString *)string 
{
    if (textField.tag == kTextFieldTagSubtotal 
        || textField.tag == kTextFieldTagSubtotalDecimal
        || textField.tag == kTextFieldTagShipping
        || textField.tag == kTextFieldTagShippingDecimal) 
    {
        [self calculateAndUpdateTextFields];

    }

    return YES;
}
Author: Juan Boero, 2011-08-10

19 answers

Desde forma correcta de hacer uitextfield text change call back :

Capto los caracteres enviados a un control UITextField algo como esto:

// Add a "textFieldDidChange" notification method to the text field control.
[textField addTarget:self 
              action:@selector(textFieldDidChange:) 
    forControlEvents:UIControlEventEditingChanged];

Luego, en el método textFieldDidChange: puede examinar el contenido del campo de texto y recargar su vista de tabla según sea necesario.

Podrías usar eso y poner calculateAndUpdateTextFields como tu selector.

 932
Author: Daniel G. Wilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-21 04:37:52

La respuesta de XenElement es acertada.

Lo anterior también se puede hacer en interface builder haciendo clic derecho en el UITextField y arrastrando el evento "Editing Changed" send a su unidad de subclase.

Evento de Cambio UITextField

 345
Author: William T.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-10 15:51:10

Para establecer el receptor de eventos:

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

Para escuchar realmente:

- (void)textFieldDidChange:(UITextField *)textField {
    NSLog(@"text changed: %@", textField.text);
}
 117
Author: asdf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-19 21:53:24

Swift:

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

Luego, implementa la función callback:

@objc func textFieldDidChange(textField: UITextField){

print("Text changed")

}
 59
Author: Juan Boero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-29 20:23:41

Como se indica aquí: Evento de cambio de texto UITextField, parece que a partir de iOS 6 (iOS 6.0 y 6.1 marcados) no es posible detectar completamente los cambios en los objetos UITextField simplemente observando el UITextFieldTextDidChangeNotification.

Parece que solo los cambios realizados directamente por el teclado iOS incorporado se rastrean ahora. Esto significa que si cambia su objeto UITextField simplemente invocando algo como esto: myUITextField.text = @"any_text", no se le notificará sobre ningún cambio en absoluto.

No se si esto es un error o es intencionado. Parece un error ya que no he encontrado ninguna explicación razonable en la documentación. Esto también se indica aquí: Evento de cambio de texto UITextField.

Mi "solución" a esto es publicar una notificación por mí mismo por cada cambio que haga en mi UITextField (si ese cambio se realiza sin usar el teclado iOS incorporado). Algo como esto:

myUITextField.text = @"I'm_updating_my_UITextField_directly_in_code";

NSNotification *myTextFieldUpdateNotification  = 
  [NSNotification notificationWithName:UITextFieldTextDidChangeNotification
                  object:myUITextField];

[NSNotificationCenter.defaultCenter 
  postNotification:myTextFieldUpdateNotification];

De esta manera, estará 100% seguro de que recibirá la misma notificación cuando cambie la propiedad .text de su objeto UITextField, ya sea cuando lo actualiza "manualmente" en su código o a través del teclado iOS incorporado.

Es importante tener en cuenta que, dado que este no es un comportamiento documentado, este enfoque puede conducir a 2 notificaciones recibidas por el mismo cambio en su objeto UITextField. Dependiendo de sus necesidades (lo que realmente hace cuando su UITextField.text cambia) esto podría ser un inconveniente para usted.

Un enfoque ligeramente diferente sería publicar una costumbre notificación (esto es, con un nombre personalizado que no sea UITextFieldTextDidChangeNotification) si realmente necesita saber si la notificación fue suya o "hecha por iOS".

EDITAR:

Acabo de encontrar un enfoque diferente, que creo que podría ser mejor:

Esto implica la Observación Clave-Valor (KVO) característica de Objective-C (http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177-BCICJDHA).

Básicamente, usted se registra como observador de una propiedad y si esta propiedad cambia, se le notifica al respecto. El "principio" es bastante similar a cómo funciona NSNotificationCenter, siendo la principal ventaja que este enfoque funciona automáticamente también a partir de iOS 6 (sin ningún ajuste especial como tener que publicar manualmente notificación).

Para nuestro UITextField-escenario esto funciona bien si agrega este código a, por ejemplo, su UIViewController que contiene el campo de texto:

static void *myContext = &myContext;

- (void)viewDidLoad {
  [super viewDidLoad];

  //Observing changes to myUITextField.text:
  [myUITextField addObserver:self forKeyPath:@"text"
    options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld 
    context:myContext];

}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
change:(NSDictionary *)change context:(void *)context {

  if(context == myContext) {
    //Here you get notified every time myUITextField's "text" property is updated
    NSLog(@"New value: %@ - Old value: %@",
      [change objectForKey:NSKeyValueChangeNewKey],
      [change objectForKey:NSKeyValueChangeOldKey]);
  }
  else 
    [super observeValueForKeyPath:keyPath ofObject:object 
      change:change context:context];

}

Crédito a esta respuesta con respecto a la gestión del" contexto": https://stackoverflow.com/a/12097161/2078512

Nota: Parece que mientras está en el proceso de editando un UITextField con el teclado iOS incorporado, la propiedad "text" del campo de texto no se actualiza con cada nueva letra mecanografiada/eliminada. En su lugar, el objeto campo de texto se actualiza "como un todo" después de renunciar al estado de primer respondedor del campo de texto.

 25
Author: ercolemtar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:49

Podemos configurarlo fácilmente desde Storyboard, CTRL arrastrar el @IBAction y cambiar el evento de la siguiente manera:

introduzca la descripción de la imagen aquí

 20
Author: bikram sapkota,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-04 15:14:26

Aquí en la versión swift para el mismo.

textField.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)

func textFieldDidChange(textField: UITextField) {

}

Gracias

 12
Author: Hindu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-01 07:02:12

Resolví el problema cambiando el comportamiento de shouldChangeChractersInRange. Si devuelve NO, iOS no aplicará los cambios internamente, en su lugar, tiene la oportunidad de cambiarlo manualmente y realizar cualquier acción después de los cambios.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    //Replace the string manually in the textbox
    textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string];
    //perform any logic here now that you are sure the textbox text has changed
    [self didChangeTextInTextField:textField];
    return NO; //this make iOS not to perform any action
}
 9
Author: Pauls,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-11 15:30:03

Versión Swift probada:

//Somewhere in your UIViewController, like viewDidLoad(){ ... }
self.textField.addTarget(
        self, 
        action: #selector(SearchViewController.textFieldDidChange(_:)),
        forControlEvents: UIControlEvents.EditingChanged
)

Parámetros explicados:

self.textField //-> A UITextField defined somewhere in your UIViewController
self //-> UIViewController
.textFieldDidChange(_:) //-> Can be named anyway you like, as long as it is defined in your UIViewController

Luego agregue el método que creó anteriormente en su UIViewController:

//Gets called everytime the text changes in the textfield.
func textFieldDidChange(textField: UITextField){

    print("Text changed: " + textField.text!)

}
 8
Author: rottenoats,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-27 07:36:12

Para Swift 3.0:

let textField = UITextField()

textField.addTarget(
    nil,
    action: #selector(MyClass.textChanged(_:)),
    for: UIControlEvents.editingChanged
)

Usando clases como:

class MyClass {
    func textChanged(sender: Any!) {

    }
}
 4
Author: pedrouan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-04 16:31:17

Swift 4

func addNotificationObservers() {

    NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChangeAction(_:)), name: .UITextFieldTextDidChange, object: nil)

}

@objc func textFieldDidChangeAction(_ notification: NSNotification) {

    let textField = notification.object as! UITextField
    print(textField.text!)

}
 3
Author: sconewolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-08 01:24:31

Debe usar la notificación para resolver este problema,porque el otro método escuchará el cuadro de entrada no la entrada real,especialmente cuando usa el método de entrada chino. En viewDidLoad

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFiledEditChanged:)
                                                 name:@"UITextFieldTextDidChangeNotification"
                                               object:youTarget];

Entonces

- (void)textFiledEditChanged:(NSNotification *)obj {
UITextField *textField = (UITextField *)obj.object;
NSString *toBestring = textField.text;
NSArray *currentar = [UITextInputMode activeInputModes];
UITextInputMode *currentMode = [currentar firstObject];
if ([currentMode.primaryLanguage isEqualToString:@"zh-Hans"]) {
    UITextRange *selectedRange = [textField markedTextRange];
    UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
    if (!position) {
        if (toBestring.length > kMaxLength)
            textField.text =  toBestring;
} 

}

Finalmente,usted corre,will hecho.

 2
Author: HsuChihYung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-25 06:42:25

Swift 3.1:

Selector: className.methodName

  cell.lblItem.addTarget(self, action: #selector(NewListScreen.fieldChanged(textfieldChange:)), for: .editingChanged)

  func fieldChanged(textfieldChange: UITextField){

    }
 2
Author: Beyaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-11 11:32:34

Con cierre:

   class TextFieldWithClosure: UITextField {
    var targetAction: (() -> Void)? {
        didSet {
            self.addTarget(self, action: #selector(self.targetSelector), for: .editingChanged)
        }
    }

    func targetSelector() {
        self.targetAction?()
    }
    }

Y usando

textField.targetAction? = {
 // will fire on text changed
 }
 2
Author: ebohdas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-21 14:46:15
[[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(didChangeTextViewText:) 
name:UITextFieldTextDidChangeNotification object:nil];



- (void) didChangeTextViewText {
 //do something
}
 1
Author: PeiweiChen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-04 06:57:28

Swift 3 Versión:

class SomeClass: UIViewController, UITextFieldDelegate { 

   @IBOutlet weak var aTextField: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        aTextField.delegate = self
        aTextField.addTarget(self, action: #selector(SignUpVC.textFieldDidChange), for: UIControlEvents.editingChanged)        
    }

   func textFieldDidChange(_ textField: UITextField) {

       //TEXT FIELD CHANGED..SECRET STUFF

   }

}

No olvide configurar el delegado.

 1
Author: Joseph Francis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-06 02:36:35

Swift 3 Version

yourTextField.addTarget(self, action: #selector(YourControllerName.textChanges(_:)), for: UIControlEvents.editingChanged)

Y obtener los cambios aquí

func textChanges(_ textField: UITextField) {
    let text = textField.text! // your desired text here
    // Now do whatever you want.
}

Espero que ayude.

 1
Author: Riajur Rahman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-04 06:58:12

Es realmente simple con observador y swift reactivo (RxCocoa y RxSwift).

Simplemente suscríbase a la propiedad text de rx, como a continuación:

myTextField.rx.text.subscribe { text in
   print("UITextFieldTextChangeEvent Text:\(text)")
}.disposed(by: disposeBag)
 0
Author: SPatel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-30 05:23:11

Swift 3

@IBAction func textfildChange(sender: UITextField) {
        if let number = sender.text {
            if number.isEmpty {

            } else {
               print(number)
            }
        }
    }
 -1
Author: Rob-4608,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-06 05:49:06