Détecter le retour arrière dans un UITextField vide

126

Existe-t-il un moyen de détecter lorsque la touche Backspace/ Deleteest enfoncée dans le clavier de l'iPhone sur un UITextFieldqui est vide? Je veux savoir quand Backspaceest pressé seulement si le UITextFieldest vide.


Sur la base de 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 handleTextFieldChangedfonction est appelée), mais toujours pas lorsque j'appuie sur la Backspacetouche dans un champ vide. Des idées?


Il semble y avoir une certaine confusion autour de cette question. Je souhaite recevoir une notification lorsque la Backspacetouche est enfoncée. C'est tout. Mais la solution doit également fonctionner lorsque le UITextFieldest déjà vide.

marcc
la source
Je pense que vous pourriez vouloir dire "seulement si le UITextField est vide" plutôt que "seulement si le clavier est vide" ...?
Steve Harrison
@Steve Harrison: merci. Mis à jour cela.
marcc
J'essaye de faire quelque chose de similaire, quelle solution avez-vous alors? Ce que je fais est un champ de texte dans une vue de défilement, lorsque je tape du texte, des suggestions sont affichées et lorsque je clique sur un, un objet étiquette est placé à gauche du champ de texte. Merci d'avance: D
Dough
Solution 2011/11 pour UITextField vide utilisant une supercherie d'exécution: bjhomer.blogspot.com/2011/11
Jano
4
Ridiculement longtemps pour quelque chose d'aussi trivial. Cela ne devrait pas être difficile.
Adam Waite

Réponses:

36

Cela peut être long, mais cela pourrait fonctionner. Essayez de définir le texte du champ de texte sur un caractère d'espace de largeur zéro \u200B. Lorsque vous appuyez sur Retour arrière sur un champ de texte qui apparaît vide, cela supprimera votre espace. Ensuite, vous pouvez simplement réinsérer l'espace.

Peut ne pas fonctionner si l'utilisateur parvient à déplacer le curseur vers la gauche de l'espace.

Andrew
la source
3
@Andrew, c'est l'approche que j'ai décidé d'adopter. Il a fallu un peu de code, mais c'est certainement efficace. Merci pour l'aide au lieu d'essayer de me dire que je fais quelque chose de mal.
marcc
2
Cette technique peut fonctionner sur iPhone> 3.1.3, mais elle est piratée et peut se casser sur les versions futures, etc. Je pense avoir trouvé une solution plus propre et plus stable pour savoir comment détecter une suppression d'une touche de clavier sur l'iPhone / iOS .
ma11hew28
6
Je peux confirmer que la suppression n'est pas détectée si l'utilisateur parvient à déplacer le curseur vers la gauche de l'espace. Si vous pouvez comprendre comment résoudre ce problème, vous devez également sous - classe UITextFieldet mettre en œuvre canPerformAction:withSender:à return NOdes select:et selectAll:actions lorsque le texte est égal à la chaîne @"\u200B".
ma11hew28
2
Le problème est que cela ne fonctionne pas pour les champs de test sécurisés. Des idées pour gérer cela?
Kyle Clegg
7
Désolé, mais cette idée est mauvaise. C'est un piratage incroyable et ne devrait pas être la réponse acceptée avec une trentaine de votes positifs. Je sous-classe UITextField à la place, comme certains des autres commentateurs l'ont mentionné.
Brian Sachetta
155

Swift 4:


Sous UITextField- classe :

// MyTextField.swift
import UIKit

protocol MyTextFieldDelegate: AnyObject {
    func textFieldDidDelete()
}

class MyTextField: UITextField {

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

}

Objectif c:


Sous UITextField- classe :

//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

Maintenant, ajoutez simplement MyTextFieldDelegate à votre UIViewControlleret définissez votre UITextFields myDelegate sur 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");
}
Jacob
la source
9
C'est la meilleure solution. La réponse acceptée est un hack. L'Objectif C est basé sur un sous-classement et cette solution l'utilise correctement pour résoudre le problème.
TJ
Qu'adviendra-t-il de mes méthodes de délégué existantes dans la ViewController classe si je définis le délégué de mon UITextFieldUIViewController
champ de texte
4
Cela ne fonctionne apparemment pas dans ios8 pour le moment, en raison de ce qui semble être un bogue Apple: devforums.apple.com/message/1045312#1045312
chug2k
1
J'ai utilisé une solution de contournement pour le bogue ios8 comme dans ma réponse et cela a fonctionné. Cela peut être utile pour ceux qui recherchent une solution.
furkan3ayraktar
1
deleteBackward()ne sera pas appelé si vous êtes return falsedanstextField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
igrrik
41

Mise à jour: voir la réponse de JacobCaraballo pour un exemple qui remplace -[UITextField deleteBackward].

Check out UITextInput, a spécifiquement UIKeyInputune deleteBackwardméthode de délégué qui est toujours appelée lorsque la touche de suppression est enfoncée. Si vous faites quelque chose de simple, vous pouvez envisager de simplement sous-classer UILabelet de le rendre conforme au UIKeyInputprotocole, comme le font SimpleTextInput et cet exemple d'iPhone UIKeyInput . Remarque: UITextInputet ses proches (y compris UIKeyInput) ne sont disponibles que dans iOS 3.2 et versions ultérieures.

ma11hew28
la source
2
C'est la bonne réponse. C'est non-hacky et très simple avec une sous-classe rapide de UITextField.
Sam le
Je viens de repérer la réponse de Jacob ci-dessous. Il en donne un exemple détaillé.
Sam
Il est à noter que cette réponse ne fonctionne pas sous iOS 5. Si le champ de texte est vide, le fait d'appuyer sur la touche Retour arrière n'appelle pas cette méthode.
jfeldman le
31

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, n'oubliez pas de modifier la propriété Classe personnalisée du champ de texte en "MyTextField"

Jeffrey Loo
la source
5
Cela devrait être la réponse acceptée. Propre, et répond réellement à la question.
Ryan Romanchuk
1
Cela répond à la question ... Tant que vous ciblez iOS 6.0+. Sur iOS 5, deleteBackward n'a tout simplement jamais été appelé sur votre sous-classe, malheureusement.
BJ Homer
2
BJ Homer, 93% des appareils sont sur iOS 6, donc ne pas cibler iOS 5 n'est généralement pas si grave.
Jonathan.
2
Je suis content d'avoir continué à faire défiler suffisamment pour trouver ceci. 100% la bonne façon de le faire aujourd'hui dans IOS 7.
MusiGenesis
J'ai vu tant d'autres réponses à cette question qui ne sont que des solutions de contournement, et pratiquement aucune d'entre elles ne traite de la situation où la touche de retour arrière est enfoncée dans un champ vide. Ceci est cependant parfait et une façon vraiment propre de le faire.
Christopher Hannah
19

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)
        }
    }
}
Ruud Visser
la source
Merci, puis-je savoir que cette méthode est recommandée par Apple ou que c'est un hack. il semble non documenté pour textfield.
kalpesh jetani
A travaillé pour moi avec un textView. merci pour le partage;)
Edouard Barbier
A travaillé pour moi lorsque le champ de texte est vide et que l'on clique sur l'espace arrière.
Ramakrishna
17

J'ai fondé une autre manière plus simple que la subclasssolution. Même c'est un peu étrange mais ça marche 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 car le résultat de la comparaison est de -8. Peut-être que je me trompe à un moment donné C Programming. Mais son bon travail;)

Jerapong Nampetch
la source
1
La course du dos n'est pas définie '\ b'. Mais si vous effectuez un débogage soigneux, vous verrez «\ 0». J'obtiens donc le résultat 0, c'est-à-dire que deux valeurs sont égales dans la méthode strcmp. const char * stoke = [texte cStringUsingEncoding: NSASCIIStringEncoding]; const char * backstroke = "\ 0"; // ceci est égal à \ b -> "\ x08"; strcmp (dos, stoke);
Yoon Lee
De plus, selon la définition de strcmp (s1, s2), renvoie 0 si s1 == s2,> 0 s1 est a lexicographiquement supérieur à s2 vice versa.
Yoon Lee
Je ne comprends pas comment cela pourrait fonctionner? @YoonLee: tu ne dis pas non plus des strcmpretours -1, 0, or 1? C'était ma compréhension.
chug2k
1
dans textview, vous détectez toujours le retour arrière même s'il n'y a pas de texte, le UITextField est différent
LolaRun
2
Ce n'est pas une UITextViewDelegateméthode UITextFieldDelegate.
pkamb
11

Essaie le delegate

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

Ensuite, vérifiez si le range.length == 1qui semble être le cas quand backspaceest frappé.

Niklas Alvaeus
la source
8
Seulement appelé lorsque le champ n'est pas vide, cependant. Notez la question d'origine. :)
Eric Goldberg
Utilisez UITextView pour cela.
Oleg
11

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

Rapide :

func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true }
Pritesh
la source
Tx - exactement ce dont j'avais besoin. Mais où est-il documenté ??
Andy Weinstein
9

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 j'ignorais les espaces arrière. Je l'ai donc fait vérifier range.length == 1avant de couper le fichier NSString. Si c'est vrai, je renvoie simplement la chaîne et je 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);
    }   
 }
Ben Call
la source
La méthode attend un booléen et non une chaîne comme valeur de retour
Pascalius
4

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
furkan3ayraktar
la source
pouvez-vous écrire le code pour swift. J'ai eu une erreur "confirmation redondante au protocole uikeyinput"
Raj Aggrawal
4

Oui, utilisez la méthode ci-dessous pour détecter le retour arrière, lorsque textField est vide.

Besoin d'ajouter UITextFieldDelegate

yourTextField.delegate = self (DOIT REQUIS)

Rapide:

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

Objectif c:

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { 
    return YES; 
}
Himanshu padia
la source
5
Cela ne m'appelle même pas. Toutes les autres méthodes de délégué sont appelées au fur et à mesure qu'un événement se produit.
Hemang
Merci mon pote. Vous l'avez cloué. :)
MS.
@ McDonal_11 Je pense que vous avez oublié de définir textfield.delegate = self of textfield.
Himanshu padia
J'ai mis. les autres méthodes déléguées d'UITextField fonctionnent correctement. Celui-ci seul ne fonctionne pas. Ce qui me manque ??
McDonal_11
3

La meilleure utilisation que j'ai trouvée pour détecter le retour arrière est de détecter lorsque l'utilisateur a appuyé sur retour arrière dans un vide UITextField. Par exemple, si vous avez des destinataires «en bulles» dans l'application de messagerie, lorsque vous appuyez sur retour arrière dans le UITextField, il sélectionne le dernier destinataire «en bulles».

Cela peut être fait de la même manière que la réponse de Jacob Caraballo. Mais dans la réponse de Jacob, s'il UITextFieldreste un caractère lorsque vous appuyez sur retour arrière, au moment où le message du délégué est reçu, le UITextFieldsera déjà vide, de sorte que vous détectez efficacement backspacesur un champ de texte avec au plus un caractère.

En fait, si vous voulez détecter backspacesur un UITextFieldavec exactement zéro caractère (vide), vous devez envoyer le message au delegateavant 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 d'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
Sam
la source
2
Pour que cela fonctionne dans iOS8 (où il y a un bogue empêchant cette méthode de délégué d'être appelée), veuillez consulter cette réponse: stackoverflow.com/a/25862878/893101 . Plus de détails sur le bogue ios8: devforums.apple.com/message/1009150#1009150
pIkEL
2

Dans iOS 6, la méthode deleteBackward est appelée sur UITextField lorsque vous appuyez sur Retour arrière, y compris lorsque le champ est vide. Vous pouvez donc sous-classer UITextField et fournir votre propre implémentation de deleteBackward (en invoquant également les super.)

Je supporte toujours iOS 5, donc j'aurai besoin d'une combinaison de la réponse d'Andrew et celle-ci.

tracy
la source
1

:) juste pour le titre "Détecter le retour arrière", où j'utilise UIKeyboardTypeNumberPad.

Je rencontre également 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 entrer que Number ou Backspace, donc 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 vous aidera.

Jason Lee
la source
C'est la même chose avec n'importe quel type de clavier.
ma11hew28
comment connecter cette méthode à mon champ de texte?
user230910
1

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 shouldChangeCharactersInRangeméthode, je suggérerais de faire ce qui 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 cool à ce sujet, c'est que, au moment où il se termine, la valeur modifiée sera déjà dans le fichier UITextField. À ce stade, vous pouvez simplement vérifier sa longueur et / ou valider en fonction de ce qu'il y a.

Aaron
la source
1

Le sous-classement 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
}
joel.d
la source
1

Dans le fichier .h, ajoutez un 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;
}   

Formatage amélioré

Anjali Prasad
la source
1

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 sur un autre champ de texte que si le champ de texte est vide lorsque vous appuyez sur 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)
    }
}
Hemang
la source
1

La réponse la plus peuplée manque une chose - la capacité de détecter si le champ de texte était vide ou non.

Autrement dit, lorsque vous remplacez 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 la vacuité avant la suppression.

1. Créez un protocole délégué qui étend UITextFieldDelegate

protocol MyTextFieldDelegate: UITextFieldDelegate {
    func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool)
}

2. Sous-classe UITextField

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

3. Implémentez votre nouveau protocole de délégué

extension MyViewController: MyTextFieldDelegate {
    func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool) {
        if wasEmpty {
            // do what you want here...
        }
    }
}
Tim
la source
1

Gestionnaire complet pour champ de texte avec numéro à un chiffre pour Swift 5.1 :

  • En supposant que vous ayez une collection de sortie de textFields (avec des délégués connectés également)

1 étape

protocol MyTextFieldDelegate: class {
    func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool) 
}

final class MyTextField: UITextField {

    weak var myDelegate: MyTextFieldDelegate?

    override func deleteBackward() {
        let wasEmpty = text == nil || text == ""

        // then perform normal behavior
        super.deleteBackward()

        // now, notify delegate (if existent)
        (delegate as? MyTextFieldDelegate)?.textField(self, didDeleteBackwardAnd: wasEmpty)
    }
}

2 étape

final class ViewController: UIViewController {

    @IBOutlet private var textFields: [MyTextField]!

    override func viewDidLoad() {
        super.viewDidLoad()
        textFields.forEach {
            $0.delegate = self
            $0.myDelegate = self
        }
    }
}

3 étape

extension ViewController: UITextFieldDelegate, MyTextFieldDelegate {
    func textFieldHasChanged(with text: String, _ tag: Int, for textField: UITextField) {
        textField.text = text

        if let someTextField = (textFields.filter { $0.tag == tag }).first {
            someTextField.becomeFirstResponder()
        } else {
            view.endEditing(true)
        }
    }

    func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool) {
        // If the user was pressing backward and the value was empty, go to previous textField
        textFieldHasChanged(with: "", textField.tag - 1, for: textField)
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        // Restrict to only digits
        let aSet = NSCharacterSet(charactersIn: "0123456789").inverted
        let compSepByCharInSet = string.components(separatedBy: aSet)
        let numberFiltered = compSepByCharInSet.joined(separator: "")

        guard string == numberFiltered, let text = textField.text else { return false }

        if text.count >= 1 && string.isEmpty {
            // If the user is deleting the value
            textFieldHasChanged(with: "", textField.tag - 1, for: textField)
        } else {
            textFieldHasChanged(with: string, textField.tag + 1, for: textField)
        }

        return false
    }
}
Latenec
la source
0

Voici ma solution basée sur l'idée @andrew:

quelque part, par exemple dans viewDidLoad

        textField.delegate = self
        textField.addTarget(self, action: #selector(valueChanged(_:)), for: .editingDidBegin)

puis

    @objc func valueChanged(_ textField: UITextField) {
        textField.text = "\u{200B}"
    }

    override func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        textField.text = string
        if string == "" {
            //backpaspace pressed 
        }
rastislv
la source
0

Vous pouvez vérifier le texte de la vue / du champ de texte pour voir s'il est vide et vous assurer que le texte de remplacement est également vide dans la méthode déléguée shouldChangeTextIn.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if (textView.text == "" && text == "") {
        print("Backspace on empty text field.")
    }
    return true
}
michael-k101
la source
-2

Quelque chose comme ça:

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

bien sûr, le hachage est pour une chaîne de caractères.

user1375355
la source
-2

À l'aide de la méthode TextField Delegate:

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

Ajoutez le code suivant dans la méthode ci-dessus pour détecter l'événement de suppression

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

Pour garder les choses simples, voici la seule condition que vous devez vérifier

     if (range.length==1)
Bhumit Mehta
la source
-3
+ (BOOL)detectBackspaceOnly:(NSString *)string
{
    for(int i=0 ; i<string.length ; i++){
        unichar caract = [string characterAtIndex:i];
        if(caract != ' ' && caract != '\n')
            return NO;
    }

    return YES;
}
K-AnGaMa
la source
2
Peut-être une petite explication où mettre cela?
Alex Cio
-4

Dans UITextViewDelegate:

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

ça marche bien pour moi.

mise à jour pour le pinyin simplifié chinois et la saisie manuscrite chinoise:

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

base sur le document dit:

"Si l'utilisateur appuie sur deleteKey, la longueur de la plage est de 1 et un objet chaîne vide remplace ce caractère unique."

joker
la source
1
Cette question concerne UITextField, non UITextView.
ma11hew28