UITextfield sans majuscules ni caractères spéciaux

Bonjour,


Je souhaite que lorsqu'un utilisateur de mon appli tape un nom dans un UITextfield il n'ait pas la possibilité d'utiliser certains caractères: interdire les espaces, les lettres en majuscule et la plupart des caractères spéciaux. (Ce champ doit me permettre d'enregistrer un identifiant sur une base de donnée).


 


En faisant des recherches j'ai trouvé des méthodes qui suivent souvent la même logique : 


définir les caractères autorisés. Voici un exemple :



#define ACCEPTABLE_CHARACTERS @abcdefghijklmnopqrstuvwxyz0123456789_.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];

NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];

return [string isEqualToString:filtered];
}


Malheureusement ça n'a pas d'effet sur mon textfield, je peux toujours taper des majuscules ou des caractères spéciaux.


Peut-être que ce que je voudrais faire n'est pas possible ? Qu'en pensez-vous ?


Réponses

  • CéroceCéroce Membre, Modérateur
    février 2017 modifié #2
    Tu as évidemment fixé textfield.delegate ?
  • Oops... merci Céroce tu m'as mis sur la voie  ::)


    c'est bon j'ai mis un delegate ça bloque les caractères tels que définis !


  • CéroceCéroce Membre, Modérateur
    Quand tu as un doute sur une méthode déléguée, commence par mettre un point d'arrêt (breakpoint) au début pour voir si elle est bien appelée.
  • Ok merci beaucoup !


    Un point de détail : j'ai ajouté une limite au nombre de caractères de cette manière (ici limité à  5) :



    #define ACCEPTABLE_CHARACTERS @abcdefghijklmnopqrstuvwxyz0123456789_.

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];

    NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
    if([textField.text length]<=5)
    return YES;
    else
    return NO;


    return [string isEqualToString:filtered];

    }


    Arrivé à  5 caractères l'utilisateur ne peut plus utiliser la touche "effacer" du clavier


    et se trouve donc bloqué s'il n'appuie pas sur le "clear button" pour effacer tout le contenu du textfield.


     


    Pas très gênant si j'autorise un grand nombre de caractères mais je pense que je ne l'ai pas écrit correctement , qu'en pensez-vous ?


  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #6

    Peut-être plus simple :



    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
    {
    if string.isEmpty // non-character comme supprimer
    {
    return true
    }

    let characterSet = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyz0123456789_.")

    return string.rangeOfCharacter(from: characterSet) != nil
    }

    ... avec fonctionnalité supprimer.


  • Joanna CarterJoanna Carter Membre, Modérateur

    Ou, si tu voulais accepter les caractères accentués :



    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
    {
    if string.isEmpty
    {
    return true
    }

    var characterSet = CharacterSet.lowercaseLetters

    characterSet.formUnion(CharacterSet.decimalDigits)

    characterSet.formUnion(CharacterSet(charactersIn: "_."))

    return string.rangeOfCharacter(from: characterSet) != nil
    }
  • Joanna CarterJoanna Carter Membre, Modérateur
    Oups ! J'ai écrit en Swift. Tu veux une traduction ?
  • Effectivement Johanna j'aimerais beaucoup avoir la même chose en obj C 


  • Joanna CarterJoanna Carter Membre, Modérateur

    OK, je suis une bonne pâte  ::)



    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
    if (textField.text.length >= 5)
    {
    return false;
    }

    if (string.length == 0)
    {
    return true;
    }

    NSMutableCharacterSet *characterSet = [NSMutableCharacterSet lowercaseLetterCharacterSet];

    [characterSet formUnionWithCharacterSet: [NSCharacterSet decimalDigitCharacterSet]];

    [characterSet formUnionWithCharacterSet: [NSCharacterSet characterSetWithCharactersInString:@_.]];

    return [string rangeOfCharacterFromSet:characterSet].location != NSNotFound;
    }

    ça compile mais je ne l'ai pas testé


  • Génial un grand merci Johanna ça fonctionne très très bien !!


  • Et en Fortran ou en Cobol ?  8--)


  • Joanna CarterJoanna Carter Membre, Modérateur
    Désolée, j'ai jeté mes cartes Hollerith ;)
  • Joanna CarterJoanna Carter Membre, Modérateur

    Génial un grand merci Johanna ça fonctionne très très bien !!




    Tu voulais inclure les caractères accentués ?
  • JérémyJérémy Membre
    février 2017 modifié #15

    Rolalalala, il y a rien à  dire, Joanna est vraiment la meilleure !




  • Tu voulais inclure les caractères accentués ?




     


    Effectivement j'ai ajouté quelques caractères accentués 


    Encore merci et bravo pour ton code (d'orfèvre)

  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #17

    Tu sais que [NSMutableCharacterSet lowercaseLetterCharacterSet] eux comprend déjà  ?




  • Tu sais que [NSMutableCharacterSet lowercaseLetterCharacterSet] eux comprend déjà  ?




     


    Ok merci, j'apprends petit à  petit 

  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #19


  • Peut-être plus simple :



    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
    {
    if string.isEmpty // non-character comme supprimer
    {
    return true
    }

    let characterSet = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyz0123456789_.")

    return string.rangeOfCharacter(from: characterSet) != nil
    }

    ... avec fonctionnalité supprimer.




    Dans le même genre de question comment puis-je ajouter un petit bout de code pour éviter la double virgule du genre "23,89" est ok


    "23,8,9" provoque un plantage système, peut-être même du Mac ?


     


    Juste une autre question dans son VC pour les "delegate" on doit incorporer a l'ouverture de la vue "monTextField.delegate = self"


    si on le fait avec le lien prévu dans IB c'est pareil ?

  • Joanna CarterJoanna Carter Membre, Modérateur
    avril 2017 modifié #21

    Tu as de la chance !


     


    Je suis en train d'achever un "DecimalTextFieldInteractor", qui fait toute la validation. Je vais le publier sur mon blog, dès que j'aie rédigé l'article.


     


    En réponse à  ton problème :



    lazy var decimalSeparatorCharacterSet: CharacterSet =
    {
    let decimalSeparator = Locale.autoupdatingCurrent.decimalSeparator ?? "."

    let decimalSeparatorCharacterSet = CharacterSet(charactersIn: decimalSeparator)

    return decimalSeparatorCharacterSet
    }()

    public func textField(_ textField: UITextField,
    shouldChangeCharactersIn range: NSRange,
    replacementString string: String) -> Bool
    {
    guard var text = textField.text,
    let decimalSeparator = Locale.autoupdatingCurrent.decimalSeparator else
    {
    return false
    }

    if string.isEmpty // backspace handling
    {
    if text.hasSuffix(decimalSeparator),
    text.hasPrefix("0") // if text only contains "0,"
    {
    textField.deleteBackward() // delete "0"

    return true // this will also delete decimal separator
    }
    }
    else // text entry
    {
    guard string.rangeOfCharacter(from: validCharacters) != nil else
    {
    return false
    }

    // check if text already has a decimal separator
    if (string == decimalSeparator) && text.rangeOfCharacter(from: decimalSeparatorCharacterSet) != nil
    {
    return false
    }

    ...
    }
    }

    Attention ! il faut utiliser Locale.autoupdatingCurrent.decimalSeparator à  la place de "," ou "."


  • Joanna CarterJoanna Carter Membre, Modérateur


    Juste une autre question dans son VC pour les "delegate" on doit incorporer a l'ouverture de la vue "monTextField.delegate = self"


    si on le fait avec le lien prévu dans IB c'est pareil ?




     


    Oui, ils sont pareils.

  • Joanna CarterJoanna Carter Membre, Modérateur

    Oh, et pour le validCharacters, je fais qqch comme :



    public lazy var validCharacters: CharacterSet =
    {
    var validCharacters = CharacterSet.decimalDigits

    validCharacters.formUnion(decimalSeparatorCharacterSet)

    return validCharacters
    }()
Connectez-vous ou Inscrivez-vous pour répondre.