En utilisant `textField: shouldChangeCharactersInRange:`, comment obtenir le texte comprenant le caractère actuellement tapé?


116

J'utilise le code ci-dessous pour essayer de faire textField2en sorte que le contenu textuel de soit mis à jour pour correspondre à textField1chaque fois que l'utilisateur tapetextField1 .

- (BOOL) textField: (UITextField *)theTextField shouldChangeCharactersInRange: (NSRange)range replacementString: (NSString *)string {    
  if (theTextField == textField1){    
     [textField2 setText:[textField1 text]];    
  }
}

Cependant, le résultat que j'observe est que ...

textField2 vaut "12", lorsque textField1 vaut "123"

textField2 est "123", lorsque textField1 est "1234"

... quand ce que je veux c'est:

textField2 est "123", lorsque textField1 est "123"

textField2 est "1234", lorsque textField1 est "1234"

Qu'est-ce que je fais mal?


8
Juste un rappel, il est incroyablement plus facile de toujours utiliser l' événement "Modification modifiée" . Faites-le simplement glisser dans IB vers une fonction que vous créez.
Fattie

Notez que l'événement de modification de modification ne capture aucun événement de modification de texte généré par programme, par exemple, correction automatique / saisie semi-automatique / remplacement de texte.
shim

Réponses:


272

-shouldChangeCharactersInRangeest appelé avant que le champ de texte ne modifie réellement son texte, c'est pourquoi vous obtenez une ancienne valeur de texte. Pour obtenir le texte après l'utilisation de la mise à jour:

[textField2 setText:[textField1.text stringByReplacingCharactersInRange:range withString:string]];

15
Cela a presque fonctionné pour moi. Si je tapais un caractère, cela fonctionnait. Si j'appuyais sur le bouton de suppression, cela supprimait deux caractères. Pour moi, la suggestion suivante a fonctionné: stackoverflow.com/questions/388237/... Fondamentalement, faites un glisser-déposer de UITextField dans votre code (pour créer une fonction), puis cliquez avec le bouton droit sur votre TextField et faites glisser'n ' drop du cercle pour le "Modification modifiée" à votre nouvelle fonction. (Soupir. Visual Studio me manque parfois ..)
Mike Gledhill

Je pense aussi que c'est une réponse valable, mais pas LA réponse. La meilleure façon d'accomplir ce que vous voulez a été répondu par @tomute
Pedro Borges

5
Ou textFiel.text = (textFiel.text as NSString) .stringByReplacingCharactersInRange (range, withString: string) en Swift
Max

@MikeGledhill Vous pouvez faire la même chose par programmation:[textField addTarget:self action:@selector(textFieldEditingChanged:) forControlEvents:UIControlEventEditingChanged]
Steve Moser

52
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString * searchStr = [textField.text stringByReplacingCharactersInRange:range withString:string];

    NSLog(@"%@",searchStr);
    return YES;
}

40

Swift 3

Sur la base de la réponse acceptée, les éléments suivants devraient fonctionner dans Swift 3 :

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    let newString = NSString(string: textField.text!).replacingCharacters(in: range, with: string)

    return true
}

Remarque

Les deux Stringet NSStringont des méthodes appelées replacingCharacters:inRange:withString. Cependant, comme prévu, le premier attend une instance de Range, tandis que le second attend une instance de NSRange. La textFieldméthode déléguée utilise une NSRangeinstance, donc l'utilisation de NSStringdans ce cas.


replacingCharactersdevrait êtrestringByReplacingCharactersInRange
Alan Scarpa

1
@Alan_s J'ai copié cet extrait directement à partir de mon projet Xcode et cela fonctionnait bien. Utilisez-vous Xcode 8.1 avec une cible vers iOS 10.1?
focorner


13

Dans Swift (4), sans NSString(Swift pur):

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    if let textFieldString = textField.text, let swtRange = Range(range, in: textFieldString) {

        let fullString = textFieldString.replacingCharacters(in: swtRange, with: string)

        print("FullString: \(fullString)")
    }

    return true
}

En extension:

extension UITextField {

    func fullTextWith(range: NSRange, replacementString: String) -> String? {

        if let fullSearchString = self.text, let swtRange = Range(range, in: fullSearchString) {

            return fullSearchString.replacingCharacters(in: swtRange, with: replacementString)
        }

        return nil
    }
}

// Usage:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    if let textFieldString = textField.fullTextWith(range: range, replacementString: string) {
        print("FullString: \(textFieldString)")
    }

    return true
}

8

Version Swift pour cela:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

    if string == " " {
        return false
    }

    let userEnteredString = textField.text

    var newString = (userEnteredString! as NSString).stringByReplacingCharactersInRange(range, withString: string) as NSString

    print(newString)

    return true
}

5

C'est le code dont vous avez besoin,

if ([textField isEqual:self.textField1])
  textField2.text = [textField1.text stringByReplacingCharactersInRange:range withString:string];

1

utiliser la garde

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        guard case let textFieldString as NSString = textField.text where
            textFieldString.stringByReplacingCharactersInRange(range, withString: string).length <= maxLength else {
                return false
        }
        return true
    }

0

Ma solution est d'utiliser UITextFieldTextDidChangeNotification.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(copyText:) name:UITextFieldTextDidChangeNotification object:nil];

Ne pas oublier d'appeler [[NSNotificationCenter defaultCenter] removeObserver:self];à la deallocméthode.


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.