Detectar backspace no UITextField vazio

Existe alguma maneira de detectar quando a tecla Backspace / Delete é pressionada no teclado do iPhone em um UITextField que está vazio? Eu quero saber quando o Backspace é pressionado somente se o UITextField estiver vazio.


Com base na sugestão do @Alex Reynolds em um comentário, adicionei o seguinte código ao criar meu campo de texto:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTextFieldChanged:) name:UITextFieldTextDidChangeNotification object:searchTextField]; 

Essa notificação é recebida (a function handleTextFieldChanged é chamada), mas ainda não quando eu pressiono a tecla Backspace em um campo vazio. Alguma ideia?


Parece haver alguma confusão em torno desta questão. Eu quero receber uma notificação quando a tecla Backspace é pressionada. É isso aí. Mas a solução também deve funcionar quando o UITextField já estiver vazio.

Isso pode ser um tiro longo, mas poderia funcionar. Tente definir o texto do campo de texto para um caractere de espaço de largura zero \u200B . Quando o backspace é pressionado em um campo de texto que aparece vazio, ele realmente excluirá seu espaço. Então você pode simplesmente reinserir o espaço.

Pode não funcionar se o usuário conseguir mover o cursor para a esquerda do espaço.

Swift 4:


Subclass UITextField :

 // MyTextField.swift import UIKit protocol MyTextFieldDelegate { func textFieldDidDelete() } class MyTextField: UITextField { var myDelegate: MyTextFieldDelegate? override func deleteBackward() { super.deleteBackward() myDelegate?.textFieldDidDelete() } } 

Implementação:

 // ViewController.swift import UIKit class ViewController: UIViewController, MyTextFieldDelegate { override func viewDidLoad() { super.viewDidLoad() // initialize textField let input = MyTextField(frame: CGRect(x: 50, y: 50, width: 150, height: 40)) // set viewController as "myDelegate" input.myDelegate = self // add textField to view view.addSubview(input) // focus the text field input.becomeFirstResponder() } func textFieldDidDelete() { print("delete") } } 

Objetivo-C:


Subclass UITextField :

 //Header //MyTextField.h //create delegate protocol @protocol MyTextFieldDelegate  @optional - (void)textFieldDidDelete; @end @interface MyTextField : UITextField //create "myDelegate" @property (nonatomic, assign) id myDelegate; @end //Implementation #import "MyTextField.h" @implementation MyTextField - (void)deleteBackward { [super deleteBackward]; if ([_myDelegate respondsToSelector:@selector(textFieldDidDelete)]){ [_myDelegate textFieldDidDelete]; } } @end 

Agora simplesmente adicione MyTextFieldDelegate ao seu UIViewController e defina seu myDelegate do UITextFields para self :

 //View Controller Header #import "MyTextField.h" //add "MyTextFieldDelegate" to you view controller @interface ViewController : UIViewController  @end //View Controller Implementation - (void)viewDidLoad { //initialize your text field MyTextField *input = [[MyTextField alloc] initWithFrame:CGRectMake(0, 0, 70, 30)]; //set your view controller as "myDelegate" input.myDelegate = self; //add your text field to the view [self.view addSubview:input]; } //MyTextField Delegate - (void)textFieldDidDelete { NSLog(@"delete"); } 

Atualização: Veja a resposta de JacobCaraballo para um exemplo que substitui -[UITextField deleteBackward] .

Confira UITextInput , especificamente UIKeyInput tem um método de delegação deleteBackward que sempre é chamado quando a tecla delete é pressionada. Se você está fazendo algo simples, então você pode considerar apenas subclassificar o UILabel e torná-lo compatível com o protocolo UIKeyInput , como feito pelo SimpleTextInput e este exemplo do iPhone UIKeyInput . Nota: UITextInput e seus parentes (incluindo UIKeyInput ) só estão disponíveis no iOS 3.2 e posterior.

Código como segue:

 @interface MyTextField : UITextField @end @implementation MyTextField - (void)deleteBackward { [super deleteBackward]; //At here, you can handle backspace key pressed event even the text field is empty } @end 

Por fim, esqueça de alterar a propriedade Custom Class do campo de texto para “MyTextField”

Eu fundei de outra forma mais fácil do que a solução de subclass . Até mesmo um pouco estranho, mas funciona bem.

 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { const char * _char = [text cStringUsingEncoding:NSUTF8StringEncoding]; int isBackSpace = strcmp(_char, "\b"); if (isBackSpace == -8) { // is backspace } return YES; } 

É um pouco estranho porque o resultado da comparação é -8. Talvez eu esteja errado em algum ponto da C Programming Mas o seu trabalho certo;)

Implementação Swift:

 import UIKit protocol PinTexFieldDelegate : UITextFieldDelegate { func didPressBackspace(textField : PinTextField) } class PinTextField: UITextField { override func deleteBackward() { super.deleteBackward() // If conforming to our extension protocol if let pinDelegate = self.delegate as? PinTexFieldDelegate { pinDelegate.didPressBackspace(self) } } } 

Experimente o delegate

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { 

Então verifique se o range.length == 1 parece ser o caso quando o backspace é atingido.

Por favor, use o código abaixo para ajudá-lo a detectar a tecla delete do teclado, mesmo que o campo de texto esteja vazio.

Objetivo C:

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { return YES; }

Rápido :

 func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true } 

A resposta de Niklas Alvaeus me ajudou com um problema semelhante

Eu estava limitando a input para um conjunto de caracteres específico, mas estava ignorando backspaces. Então eu fiz o check range.length == 1 antes de cortar o NSString . Se é verdade, apenas retorno a string e não a apare. Ver abaixo

  - (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { NSCharacterSet *nonNumberSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]; if (range.length == 1) { return string; } else { return ([string stringByTrimmingCharactersInSet:nonNumberSet].length > 0); } } 

Para aqueles que têm problemas com a resposta de Jacob, eu implementei minha subclass textfield como segue e ela funciona muito bem!

 #import  @class HTTextField; @protocol HTBackspaceDelegate  @optional - (void)textFieldDidBackspace:(HTTextField*)textField; @end @interface HTTextField : UITextField @property (nonatomic, assign) id backspaceDelegate; @end #import "HTTextField.h" @implementation HTTextField - (void)deleteBackward { [super deleteBackward]; if ([self.backspaceDelegate respondsToSelector:@selector(textFieldDidBackspace:)]){ [self.backspaceDelegate textFieldDidBackspace:self]; } } - (BOOL)keyboardInputShouldDelete:(UITextField *)textField { BOOL shouldDelete = YES; if ([UITextField instancesRespondToSelector:_cmd]) { BOOL (*keyboardInputShouldDelete)(id, SEL, UITextField *) = (BOOL (*)(id, SEL, UITextField *))[UITextField instanceMethodForSelector:_cmd]; if (keyboardInputShouldDelete) { shouldDelete = keyboardInputShouldDelete(self, _cmd, textField); } } if (![textField.text length] && [[[UIDevice currentDevice] systemVersion] intValue] >= 8) { [self deleteBackward]; } return shouldDelete; } @end 

Sim, use o método abaixo para detectar backspace, quando textField estiver vazio.

Precisa adicionar UITextFieldDelegate

yourTextField.delegate = self (DEVE NECESSÁRIO)

Rápido:

 func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true } 

Objetivo C:

 - (BOOL)keyboardInputShouldDelete:(UITextField *)textField { return YES; } 

O melhor uso que encontrei para detectar backspace é detectar quando o usuário pressionou o backspace em um UITextField vazio. Por exemplo, se você tiver ‘borbulhado’ destinatários no aplicativo de e-mail, quando você clicar em retroceder no UITextField , ele selecionará o último destinatário ‘borbulhado’.

Isso pode ser feito de maneira semelhante à resposta de Jacob Caraballo. Mas na resposta de Jacob, se o UITextField tiver um caractere restante quando você clicar no retrocesso, no momento em que a mensagem delegada for recebida, o UITextField já estará vazio, então você está efetivamente detectando backspace em um campo de texto com no máximo um caractere.

Na verdade, se você quiser detectar backspace em um UITextField com exatamente zero caracteres (vazio), então você deve enviar a mensagem para o delegate antes da chamada para super deleteBackward . Por exemplo:

 #import "MyTextField.h" //Text field that detects when backspace is hit with empty text @implementation MyTextField #pragma mark - UIKeyInput protocol -(void)deleteBackward { BOOL isTextFieldEmpty = (self.text.length == 0); if (isTextFieldEmpty) { if ([self.delegate respondsToSelector:@selector(textFieldDidHitBackspaceWithEmptyText:)]) { [self.delegate textFieldDidHitBackspaceWithEmptyText:self]; } } [super deleteBackward]; } @end 

A interface para tal campo de texto seria algo como isto:

 @protocol MyTextFieldDelegate; @interface MyTextField : UITextField @property(nonatomic, weak) id delegate; @end @protocol MyTextFieldDelegate  @optional -(void)textFieldDidHitBackspaceWithEmptyText:(MyTextField *)textField; @end 

No iOS 6, o método deleteBackward é chamado no UITextField quando o backspace é pressionado, inclusive quando o campo está vazio. Assim você pode subclassificar o UITextField e fornecer sua própria implementação deleteBackward (invocando o super também).

Eu ainda estou suportando o iOS 5, então vou precisar de uma combinação da resposta de Andrew e isso.

🙂 apenas para o título “Detect backspace”, onde eu uso o UIKeyboardTypeNumberPad .

Eu também encontro a mesma pergunta hoje à noite, e segue o meu código para descobrir:

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { NSLog([NSString stringWithFormat:@"%d", [string length]]); } 

Como com o UIKeyboardTypeNumberPad , o usuário só pode inserir Number ou backspace, portanto, quando o comprimento da string for 0, ele deverá ser a tecla backspace.

Espero que o acima vai fazer alguma ajuda.

Em vez de tentar pré-estruturar o que SERÁ no campo de texto ou descobrir qual caractere especial foi inserido no método shouldChangeCharactersInRange , sugiro fazer o seguinte:

 [self performSelector:@selector(manageSearchResultsDisplay) withObject:nil afterDelay:0]; 

Isso permite que você chame um método diretamente após a conclusão da operação atual. O que é legal sobre isso é que, quando ele for concluído, o valor modificado já estará no UITextField . Nesse ponto, você pode apenas verificar seu tamanho e / ou validar com base no que está lá.

Subclassing UITextField não funcionou para mim no iOS 8.3, deleteBackward nunca foi chamado.

Aqui está a solução que usei, funciona em todas as versões do iOS 8 e também deve funcionar em outras versões do iOS

 for textField in textFields { textField.text = " " } func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if string == "" && textField.text == " " { // Do stuff here return false } return true } 

No arquivo .h, adicione o delegado UIKeyInput

 - (BOOL)keyboardInputShouldDelete:(UITextField *)textField { if ([textField isEqual:_txtFirstDigit]) { }else if([textField isEqual:_txtSecondDigit]) { [_txtFirstDigit becomeFirstResponder]; }else if([textField isEqual:_txtThirdDigit]) { [_txtSecondDigit becomeFirstResponder]; }else if([textField isEqual:_txtFourthDigit]) { [_txtThirdDigit becomeFirstResponder]; } return YES; } 

formatação aprimorada

Implementei a solução semelhante com pequenas melhorias que me dirão que se o campo de texto tiver algum valor enquanto o usuário toca no backspace. Isso é útil para o meu caso, quando eu deveria focar apenas em outro campo de texto se o campo de texto estiver vazio quando o backspace for pressionado.

 protocol MyTextFieldDelegate : UITextFieldDelegate { func textFieldDidDelete(textField: MyTextField, hasValue: Bool) } override func deleteBackward() { let currentText = self.text ?? "" super.deleteBackward() let hasValue = currentText.isEmpty ? false : true if let delegate = self.delegate as? MyTextFieldDelegate { delegate.textFieldDidDelete(textField: self, hasValue: hasValue) } } 

Usando o método Delegado TextField:

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 

Adicione o seguinte código no método acima para detectar o evento de exclusão

 if(textField == YourTextField) { if ([string length] == 0 && range.length > 0) { // Your Code after deletion of character } } 

Para mantê-lo simples aqui é a única condição que você precisa verificar

  if (range.length==1) 
 + (BOOL)detectBackspaceOnly:(NSString *)string { for(int i=0 ; i 

Algo assim:

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (![text hash] && ![textField.text length]) [self backspaceInEmptyTextField]; } 

é claro que o hash é para uma cadeia de caracteres.

Em UITextViewDelegate :

 - (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { if(text isEqualToString:@""); { NSLog(@"press backspace."); } } 

funciona bem para mim.

atualização para chinês simplificado pinyin e input de texto manuscrito chinês:

 - (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { if (range.length > 0 && [text isEqualToString:@""]) { NSLog(@"press Backspace."); } return YES; } 

base no documento diz:

“Se o usuário pressionar o deleteKey , o comprimento do intervalo é 1 e um object de string vazia substitui esse caractere único.”