web-dev-qa-db-fra.com

Comment détecter la clé de suppression sur un UITextField dans iOS 8?

J'ai sous-classé UITextField et implémenté la méthode deleteBackward du protocole UIKeyInput pour détecter le retour arrière pressé. Cela fonctionne bien sur iOS 7 mais pas sur iOS 8.

deleteBackward n'est plus appelé sur UITextField lorsque j'appuie sur la touche de retour arrière.

J'ai vérifié la documentation et les notes de publication et rien n'indique la raison pour laquelle cela pourrait se produire. Des pointeurs?

37
VNVN

Vous devez chercher un exemple pour MBContactPicker sur github. Suppression de contacts chez MBContactPicker via le bouton Retour arrière sur iOS8 testé par moi. Et ça marche énormément! Vous pouvez l'utiliser comme exemple.

L'auteur de MBContactPicker utilise la méthode suivante: lorsque UITextField doit devenir vide (ou avant d'appeler devientFirstResponder lorsqu'il est vide), il y enregistre un seul symbole d'espacement. Et puis, lorsque vous appuyez sur le bouton Retour arrière (lorsque le focus a été défini sur la fin du texte de votre UITextField), la méthode

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

marchera. À l'intérieur, vous devez utiliser un chèque comme celui-ci:

NSString *resultString = [textField.text stringByReplacingCharactersInRange:range withString:string];
BOOL isPressedBackspaceAfterSingleSpaceSymbol = [string isEqualToString:@""] && [resultString isEqualToString:@""] && range.location == 0 && range.length == 1;
if (isPressedBackspaceAfterSingleSpaceSymbol) {
    //  your actions for deleteBackward actions
}

Ainsi, vous devez toujours contrôler que UITextField contient un seul espace blanc.

Ce n'est pas du hack. Ainsi, l'utilisateur ne remarquera pas qu'un comportement a été modifié

12
iVader

Beaucoup de gens ont dit que c'était un bug, mais étant donné que ce problème existe toujours dans le GM je commence à penser que cela pourrait être un changement de logique. Cela dit, je a écrit ce morceau de code pour mon application et l'ai testé sur iOS 7-8.

Ajoutez la méthode suivante à votre sous-classe UITextField.

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

    BOOL isIos8 = ([[[UIDevice currentDevice] systemVersion] intValue] == 8);
    BOOL isLessThanIos8_3 = ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3f);

    if (![textField.text length] && isIos8 && isLessThanIos8_3) {
        [self deleteBackward];
    }

    return shouldDelete;
}

Ce code est légèrement avant la ligne rouge des API privées, mais vous ne devriez pas avoir de problème à l'utiliser. Mon application avec ce code est dans l'App Store.

Pour expliquer un peu, on appelait la super implémentation de cette méthode pour éviter de perdre du code. Après allaient appeler -deleteBackward s'il n'y a pas de texte et que la version iOS se situe entre 8 et 8.2.

MODIFIER : 1/22/15

Il peut également être utile de sous-classer le -deleteBackward méthode de votre sous-classe UITextField. Cela corrige quelques bogues conditionnels. L'une étant si vous utilisez un clavier personnalisé. Voici un exemple de la méthode.

- (void)deleteBackward {
    BOOL shouldDismiss = [self.text length] == 0;

    [super deleteBackward];

    if (shouldDismiss) {
        if ([self.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
            [self.delegate textField:self shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@""];
        }
    }
}

MODIFIER : 13/04/15

Comme l'a commenté @ Gee.E, iOS 8.3 a résolu ce problème. Le code a été mis à jour pour refléter les changements.

47
cnotethegr8

Vous pouvez détecter quand l'utilisateur supprime du texte en utilisant le retour arrière en implémentant la méthode déléguée UITextField:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (range.length==1 && string.length==0)
        NSLog(@"backspace tapped");

    return YES;
}
22
almas

Swift 2.2:

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

    if text == "" {
      print("Backspace has been pressed")
    }

    return true
}
5
Vladimir Vozniak

Dans iOS8, certains claviers personnalisés suppriment Word entier, donc vérifiez uniquement que string.length est OK.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (string.length==0) { //Delete any cases
       if(range.length > 1){
          //Delete whole Word
       }
       else if(range.length == 1){
          //Delete single letter
       }
       else if(range.length == 0){
          //Tap delete key when textField empty
       }  
    }  
    return YES;
}
5
LE SANG

Cela ne répond pas explicitement à la question d'origine mais ne vaut rien que dans la documentation de textField(_:shouldChangeCharactersIn:replacementString:), il soit dit:

"string: chaîne de remplacement pour la plage spécifiée. Pendant la saisie, ce paramètre contient normalement uniquement le nouveau caractère unique qui a été saisi, mais il peut contenir plus de caractères si l'utilisateur colle du texte. Lorsque l'utilisateur en supprime un ou plusieurs caractères, la chaîne de remplacement est vide. "

Ainsi, nous pouvons détecter les backspaces dans un UITextFieldDelegate si nous implémentons textField(_:shouldChangeCharactersIn:replacementString:) et vérifier si la longueur de string est 0.

Beaucoup d'autres réponses ici ont utilisé cette même logique sans faire référence à la documentation, alors espérons que le faire directement de la source rend les gens plus à l'aise de l'utiliser.

2
Brian Sachetta

Version Swift 2.0 pour la détection de la suppression basée sur BackSpace, référence au post de code d'Almas

//For Detecting Backspace based Deletion of Entire Word in TextField
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { 
    if (range.length == 1 && string.isEmpty){
        print("Used Backspace")
    }
return true
}
1
Abhijeet

Swift 2:

if (string.characters.count == 0 && range.length == 1) {
            return true
}

vous devez utiliser comme ceci string.characters.count

0
fatihyildizhan
- (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;

}

Fondamentalement, cette méthode détecte le bouton sur lequel vous appuyez (ou que vous venez d'appuyer). Cette entrée se présente sous la forme d'une chaîne NSString. Nous convertissons cette chaîne NSString en un type C char, puis la comparons au caractère de retour arrière traditionnel (\ b). Ensuite, si ce strcmp est égal à -8, nous pouvons le détecter comme un retour arrière.

0
mars