textfielddidchange shouldchangecharactersin begin ios swift cocoa-touch uikit uitextfielddelegate

ios - shouldchangecharactersin - uitextfield begin editing swift



Detectar evento de retroceso en UITextField (11)

Swift 4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let char = string.cString(using: String.Encoding.utf8)! let isBackSpace = strcmp(char, "//b") if isBackSpace == -92 { print("Backspace was pressed") return false } }

Estoy buscando soluciones sobre cómo capturar un evento de retroceso, la mayoría de las respuestas de desbordamiento de pila están en Objective-C, pero las necesito en el lenguaje Swift.

Primero he establecido el delegado para el UITextField y lo configuro en auto

self.textField.delegate = self;

Entonces sé que shouldChangeCharactersInRange usar el método delegado shouldChangeCharactersInRange para detectar si se presionó un retroceso cuando todo el código está en Objective-C. Necesito en Swift estos métodos de la siguiente manera se utiliza.

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { const char * _char = [string cStringUsingEncoding:NSUTF8StringEncoding]; int isBackSpace = strcmp(_char, "/b"); if (isBackSpace == -8) { // NSLog(@"Backspace was pressed"); } return YES; }


Swift 4

Encuentro la comparación usando strcmp irrelevante. Ni siquiera sabemos cómo está funcionando strcmp detrás de las campanas. En todas las demás respuestas, al comparar los resultados de char y /b actuales, se encuentran -8 en el objetivo-C y -92 en Swift. Escribí esta respuesta porque las soluciones anteriores no funcionaron para mí. (Xcode versión 9.3 (9E145) usando Swift 4.1 )

Para su información: cada carácter que escriba es una matriz de 1 o más elementos en la utf8 Encoding . El carácter backSpace es [0] . Puedes probar esto.

PD: No olvide asignar los delegates adecuados a sus textFields .

public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let char = string.cString(using: String.Encoding.utf8)! if (char.elementsEqual([0])) { print("Backspace was pressed") } else { print("WHAT DOES THE FOX SAY ?/n") print(char) } return true }


Implementé esta característica:

Y en el caso de que el último archivo de texto esté vacío, solo quiero cambiar al texto anterior de archivo. Intenté todas las respuestas anteriores, pero nadie funciona bien en mi situación. Por alguna razón, si agrego más lógica que print en isBackSpace == -92 paréntesis bloquean este método simplemente dejó de funcionar ...

En cuanto a mí el método a continuación es más elegante y funciona a la perfección:

Rápido

class YourTextField: UITextField { // MARK: Life cycle override func awakeFromNib() { super.awakeFromNib() } // MARK: Methods override func deleteBackward() { super.deleteBackward() print("deleteBackward") } }

Gracias @LombaX por la answer


La esperanza te ayudará: p

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { let char = string.cStringUsingEncoding(NSUTF8StringEncoding)! let isBackSpace = strcmp(char, "//b") if (isBackSpace == -92) { println("Backspace was pressed") } return true }


Por favor no destruyas tu código. Simplemente ponga esta extensión en algún lugar de su código. (Swift 4.1)

extension String { var isBackspace: Bool { let char = self.cString(using: String.Encoding.utf8)! return strcmp(char, "//b") == -92 } }

Y luego solo úsalo en tus funciones

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if string.isBackspace { // do something } return true }


Prefiero subclasificar UITextField y anular deleteBackward() porque es mucho más confiable que el hackeo de usar shouldChangeCharactersInRange :

class MyTextField: UITextField { override public func deleteBackward() { if text == "" { // do something when backspace is tapped/entered in an empty text field } // do something for every backspace super.deleteBackward() } }

La piratería shouldChangeCharactersInRange combinada con un carácter invisible que se coloca en el campo de texto tiene varias desventajas:

  • con un teclado adjunto, uno puede colocar el cursor antes de que el carácter invisible y el retroceso no se detecte más,
  • el usuario puede incluso seleccionar ese carácter invisible (usando la Shift Arrow en un teclado o incluso tocando el cursor) y se confundirá con ese personaje extraño,
  • la barra de autocompletar ofrece opciones extrañas siempre y cuando solo haya este personaje invisible,
  • el placeholder ya no se muestra,
  • el botón de borrar se muestra incluso cuando no debería hacerlo para clearButtonMode = .whileEditing .

Por supuesto, anular deleteBackward() es un poco inconveniente debido a la necesidad de deleteBackward() subclases. ¡Pero la mejor experiencia de usuario hace que valga la pena el esfuerzo!

Y si la subclasificación es un no-go, por ejemplo, cuando se utiliza UISearchBar con su UITextField incorporado, el método swizzling también debería estar bien.


Prueba esto

public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if(string == "") { print("Backspace pressed"); return true; } }

Nota: Puede devolver " verdadero " si desea permitir el retroceso. De lo contrario puede devolver " falso ".


Si necesita detectar retroceso incluso en el campo de texto vacío (por ejemplo, en caso de que necesite cambiar automáticamente a texto anterior) al presionar retroceso, puede usar una combinación de métodos propuestos: agregar un signo invisible y usar el método de delegado estándar textField:shouldChangeCharactersInRange:replacementString: como seguir

  1. Crear signo invisible

    private struct Constants { static let InvisibleSign = "/u{200B}" }

  2. Establecer delegado para textField

    textField.delegate = self

  3. En el evento EditingChanged verifica el texto y, si es necesario, agrega un símbolo invisible, como sigue:

    @IBAction func didChangeEditingInTextField(sender: UITextField) { if var text = sender.text { if text.characters.count == 1 && text != Constants.InvisibleSign { text = Constants.InvisibleSign.stringByAppendingString(text) sender.text = text } } }

  1. Agregar implementación del método delegado textField:shouldChangeCharactersInRange:replacementString:

    extension UIViewController : UITextFieldDelegate { // MARK: - UITextFieldDelegate func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { let char = string.cStringUsingEncoding(NSUTF8StringEncoding)! let isBackSpace = strcmp(char, "//b") if (isBackSpace == -92) { if var string = textField.text { string = string.stringByReplacingOccurrencesOfString(Constants.InvisibleSign, withString: "") if string.characters.count == 1 { //last visible character, if needed u can skip replacement and detect once even in empty text field //for example u can switch to prev textField //do stuff here } } } return true } }


Swift 4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { //MARK:- If Delete button click let char = string.cString(using: String.Encoding.utf8)! let isBackSpace = strcmp(char, "//b") if (isBackSpace == -92) { print("Backspace was pressed") return true } }


En swift 3

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { let char = string.cString(using: String.Encoding.utf8)! let isBackSpace = strcmp(char, "//b") if (isBackSpace == -92) { print("Backspace was pressed") } return true }

:)


Swift 4: si el usuario presiona el botón de retroceso, la cadena está vacía, por lo que este enfoque obliga a textField a aceptar solo caracteres de un conjunto de caracteres específico (en este caso, caracteres utf8) y espacios en retroceso (caso string.isEmpty).

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if string.cString(using: String.Encoding.utf8) != nil { return true } else if string.isEmpty { return true } else { return false } }