Y at-il un moyen de détecter quand le Backspace/Delete La touche est enfoncée dans le clavier de l'iPhone sur un UITextField
qui est vide? Je veux savoir quand Backspace n'est enfoncé que si le UITextField
est vide.
D'après la suggestion de @Alex Reynolds dans un commentaire, j'ai ajouté le code suivant lors de la création de mon champ de texte:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleTextFieldChanged:)
name:UITextFieldTextDidChangeNotification
object:searchTextField];
Cette notification est reçue (la fonction handleTextFieldChanged
est appelée), mais pas quand je presse le Backspace clé dans un champ vide. Des idées?
Il semble y avoir une certaine confusion autour de cette question. Je souhaite recevoir une notification lorsque le Backspace la touche est enfoncée. C'est ça. Mais la solution doit également fonctionner lorsque le UITextField
est déjà vide.
Cela peut être long mais cela pourrait marcher. Essayez de définir le texte du champ de texte sur un caractère de largeur nulle \u200B
. Lorsque vous appuyez sur la touche Retour arrière sur un champ de texte qui semble vide, votre espace sera supprimé. Ensuite, vous pouvez simplement réinsérer l'espace.
Peut ne pas fonctionner si l'utilisateur parvient à déplacer le curseur à gauche de l'espace.
Sous-classe UITextField
:
// MyTextField.Swift
import UIKit
protocol MyTextFieldDelegate {
func textFieldDidDelete()
}
class MyTextField: UITextField {
var myDelegate: MyTextFieldDelegate?
override func deleteBackward() {
super.deleteBackward()
myDelegate?.textFieldDidDelete()
}
}
La mise en oeuvre:
// 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")
}
}
Sous-classe UITextField
:
//Header
//MyTextField.h
//create delegate protocol
@protocol MyTextFieldDelegate <NSObject>
@optional
- (void)textFieldDidDelete;
@end
@interface MyTextField : UITextField<UIKeyInput>
//create "myDelegate"
@property (nonatomic, assign) id<MyTextFieldDelegate> myDelegate;
@end
//Implementation
#import "MyTextField.h"
@implementation MyTextField
- (void)deleteBackward {
[super deleteBackward];
if ([_myDelegate respondsToSelector:@selector(textFieldDidDelete)]){
[_myDelegate textFieldDidDelete];
}
}
@end
Ajoutez maintenant simplement MyTextFieldDelegate à votre UIViewController
et définissez votre UITextFields
myDelegate à self
:
//View Controller Header
#import "MyTextField.h"
//add "MyTextFieldDelegate" to you view controller
@interface ViewController : UIViewController <MyTextFieldDelegate>
@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");
}
Mise à jour: voir réponse de JacobCaraballo pour un exemple qui remplace -[UITextField deleteBackward]
.
Vérifier UITextInput
, plus précisément UIKeyInput
a une deleteBackward
méthode déléguée que toujours est appelé lorsque vous appuyez sur la touche Suppr. Si vous faites quelque chose de simple, vous pouvez alors envisager de simplement sous-classer UILabel
et de le rendre conforme au protocole UIKeyInput
, comme cela est fait par SimpleTextInput et cela Exemple pour iPhone UIKeyInput . Remarque: UITextInput
et ses parents (y compris UIKeyInput
) ne sont disponibles que dans iOS 3.2 et versions ultérieures.
Code comme suit:
@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
Enfin, oubliez de modifier la propriété Custom Class du champ de texte en "MyTextField"
Mise en œuvre rapide:
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)
}
}
}
J'ai trouvé un moyen plus simple que la solution subclass
. Même son petit peu étrange mais ça fonctionne bien.
- (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;
}
C'est un peu étrange pour le résultat de comparer est -8. Peut-être que je me trompe à un moment donné de C Programming
. Mais son bon travail;)
Essayez le delegate
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
Puis vérifiez si le range.length == 1
_ qui semble être le cas lorsque backspace
est touché.
veuillez utiliser le code ci-dessous, il vous aidera à détecter la touche de suppression du clavier, même si votre champ de texte est vide.
Objectif C:
- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { return YES; }
Swift:
func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true }
La réponse de Niklas Alvaeus m'a aidé avec un problème similaire
Je limitais l'entrée à un jeu de caractères spécifique, mais il ignorait les espaces de retour. Alors je l'ai fait vérifier range.length == 1
avant de couper le NSString
. Si c'est vrai, je retourne juste la chaîne et ne la coupe pas. Voir ci-dessous
- (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);
}
}
Oui, utilisez la méthode ci-dessous pour détecter le retour arrière lorsque textField est vide.
Besoin d'ajouter ITextFieldDelegate
yourTextField.delegate = self (DOIT OBLIGER)
Swift:
func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true }
Objectif C:
- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { return YES; }
Pour ceux qui ont des problèmes avec la réponse de Jacob , j'ai implémenté ma sous-classe textfield comme suit et cela fonctionne très bien!
#import <UIKit/UIKit.h>
@class HTTextField;
@protocol HTBackspaceDelegate <NSObject>
@optional
- (void)textFieldDidBackspace:(HTTextField*)textField;
@end
@interface HTTextField : UITextField<UIKeyInput>
@property (nonatomic, assign) id<HTBackspaceDelegate> 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
La meilleure utilisation que j'ai trouvée pour détecter le retour arrière est la détection lorsque l'utilisateur a appuyé sur le retour arrière dans un UITextField
vide. Par exemple, si vous avez des destinataires "bouillonnés" dans l'application de messagerie, lorsque vous appuyez sur la touche retour arrière dans le UITextField
, le dernier destinataire "bouillonné" est sélectionné.
Cela peut être fait de manière similaire à la réponse de Jacob Caraballo. Mais dans la réponse de Jacob, si le UITextField
a encore un caractère lorsque vous appuyez sur la touche Retour arrière, au moment où le message de délégué est reçu, le UITextField
sera déjà vide, vous détecterez donc le backspace
sur un champ de texte comportant au plus un caractère.
En fait, si vous voulez détecter backspace
sur un UITextField
avec exactement zéro caractère (vide), vous devez alors envoyer le message à delegate
avant l'appel à super deleteBackward
. Par exemple:
#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
L'interface pour un tel champ de texte ressemblerait à ceci:
@protocol MyTextFieldDelegate;
@interface MyTextField : UITextField
@property(nonatomic, weak) id<MyTextFieldDelegate> delegate;
@end
@protocol MyTextFieldDelegate <UITextFieldDelegate>
@optional
-(void)textFieldDidHitBackspaceWithEmptyText:(MyTextField *)textField;
@end
Dans iOS 6, la méthode deleteBackward est appelée sur UITextField lorsque l'utilisateur appuie sur la touche Retour arrière, y compris lorsque le champ est vide. Ainsi, vous pouvez sous-classer UITextField et fournir votre propre implémentation deleteBackward (en appelant également les super.)
Je supporte toujours iOS 5, alors il me faut une combinaison de la réponse d'Andrew et de celle-ci.
:) juste pour le titre "Detect backspace", où j'utilise UIKeyboardTypeNumberPad
.
Je rencontre aussi la même question ce soir, et voici mon code pour le découvrir:
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
{
NSLog([NSString stringWithFormat:@"%d", [string length]]);
}
Parce qu'avec UIKeyboardTypeNumberPad
, l'utilisateur ne peut saisir que le numéro ou le retour arrière. Ainsi, lorsque la longueur de la chaîne est 0, il doit s'agir d'une touche de retour arrière.
J'espère que ce qui précède aidera.
Plutôt que d'essayer de préconstruire ce qui SERA dans le champ de texte ou de déterminer quel caractère spécial a été entré dans la méthode shouldChangeCharactersInRange
, je suggère de procéder comme suit:
[self performSelector:@selector(manageSearchResultsDisplay)
withObject:nil
afterDelay:0];
Cela vous permet d'appeler une méthode directement après la fin de l'opération en cours. Ce qui est bien à ce sujet, c’est que, à la fin de celle-ci, la valeur modifiée sera déjà dans le UITextField
. À ce stade, vous pouvez simplement vérifier sa longueur et/ou valider en fonction de ce qui est disponible.
Dans le fichier .h, ajoutez le délégué 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;
}
amélioration du formatage
La réponse la plus populaire Il manque une chose - la capacité de détecter si le champ de texte était vide ou non.
En d’autres termes, lorsque vous substituez la méthode deleteBackwards () d’une sous-classe TextField, vous ne savez toujours pas si le champ de texte était déjà vide. (Avant et après deleteBackwards (), textField.text!
est une chaîne vide: ""
)
Voici mon amélioration, avec un contrôle de vide avant la suppression.
protocol MyTextFieldDelegate: UITextFieldDelegate {
func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool)
}
class MyTextField: UITextField {
override func deleteBackward() {
// see if text was empty
let wasEmpty = text == nil || text! == ""
// then perform normal behavior
super.deleteBackward()
// now, notify delegate (if existent)
(delegate as? MyTextFieldDelegate)?.textField(self, didDeleteBackwardAnd: wasEmpty)
}
}
extension MyViewController: MyTextFieldDelegate {
func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool) {
if wasEmpty {
// do what you want here...
}
}
}
La sous-classe UITextField ne fonctionnait pas pour moi sur iOS 8.3, deleteBackward n'a jamais été appelé.
Voici la solution que j'ai utilisée, fonctionne sur toutes les versions d'iOS 8 et devrait également fonctionner sur d'autres versions d'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
}
J'ai implémenté la solution similaire avec des améliorations mineures qui me diront que si le champ de texte a une valeur alors que l'utilisateur a tapé sur le retour arrière. Ceci est utile dans mon cas lorsque je ne devrais me concentrer que sur un autre champ de texte si celui-ci est vide lorsque vous appuyez sur la touche Retour arrière.
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)
}
}