web-dev-qa-db-fra.com

Longueur maximale UITextField

Quand j'ai essayé Comment définir le nombre maximum de caractères pouvant être entrés dans un UITextField à l'aide de swift? , j'ai vu que si j'utilise tous les 10 caractères, je ne peux pas effacer le caractère aussi .

La seule chose que je peux faire est d'annuler l'opération (supprimer tous les caractères ensemble).

Est-ce que quelqu'un sait comment ne pas bloquer le clavier (pour que je ne puisse pas ajouter d'autres lettres/symboles/chiffres, mais que je puisse utiliser le retour arrière)?

104
Giorgio Nocera

Avec Swift 5 et iOS 12, essayez l'implémentation suivante de la méthode textField(_:shouldChangeCharactersIn:replacementString:) qui fait partie du protocole UITextFieldDelegate:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let textFieldText = textField.text,
        let rangeOfTextToReplace = Range(range, in: textFieldText) else {
            return false
    }
    let substringToReplace = textFieldText[rangeOfTextToReplace]
    let count = textFieldText.count - substringToReplace.count + string.count
    return count <= 10
}
  • La partie la plus importante de ce code est la conversion de range (NSRange) en rangeOfTextToReplace (Range<String.Index>). Consultez ce didacticiel vidéo pour comprendre pourquoi cette conversion est importante.
  • Pour que ce code fonctionne correctement, vous devez également définir la valeur de textFieldsmartInsertDeleteType sur UITextSmartInsertDeleteType.no. Cela empêchera l'insertion éventuelle d'un espace supplémentaire (non désiré) lors d'une opération de collage.

L'exemple de code complet ci-dessous montre comment implémenter textField(_:shouldChangeCharactersIn:replacementString:) dans un UIViewController:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var textField: UITextField! // Link this to a UITextField in Storyboard

    override func viewDidLoad() {
        super.viewDidLoad()

        textField.smartInsertDeleteType = UITextSmartInsertDeleteType.no
        textField.delegate = self
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard let textFieldText = textField.text,
            let rangeOfTextToReplace = Range(range, in: textFieldText) else {
                return false
        }
        let substringToReplace = textFieldText[rangeOfTextToReplace]
        let count = textFieldText.count - substringToReplace.count + string.count
        return count <= 10
    }

}
263
Imanou Petit

Je le fais comme ça:

func checkMaxLength(textField: UITextField!, maxLength: Int) {
    if (countElements(textField.text!) > maxLength) {
        textField.deleteBackward()
    }
}

Le code fonctionne pour moi. Mais je travaille avec le storyboard. Dans Storyboard, j'ajoute une action pour le champ de texte dans le contrôleur de vue sur modification modifiée.

44
Martin

Mise à jour pour Swift 4

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
     guard let text = textField.text else { return true }
     let newLength = text.count + string.count - range.length
     return newLength <= 10
}
28
Shan Ye

Ajouter plus de détails de la réponse @Martin

// linked your button here
@IBAction func mobileTFChanged(sender: AnyObject) {
    checkMaxLength(sender as! UITextField, maxLength: 10)
}

// linked your button here
@IBAction func citizenTFChanged(sender: AnyObject) {
    checkMaxLength(sender as! UITextField, maxLength: 13)
}

func checkMaxLength(textField: UITextField!, maxLength: Int) {
    // Swift 1.0
    //if (count(textField.text!) > maxLength) {
    //    textField.deleteBackward()
    //}
    // Swift 2.0
    if (textField.text!.characters.count > maxLength) {
        textField.deleteBackward()
    }
}
14
Sruit A.Suk
func checkMaxLength(textField: UITextField!, maxLength: Int) {
        if (textField.text!.characters.count > maxLength) {
            textField.deleteBackward()
        }
}

un petit changement pour IOS 9

7
Jeremy Andrews

Dans Swift 4

Limite de 10 caractères pour le champ de texte et permettre la suppression (retour arrière)

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if textField ==  userNameFTF{
            let char = string.cString(using: String.Encoding.utf8)
            let isBackSpace = strcmp(char, "\\b")
            if isBackSpace == -92 {
                return true
            }
            return textField.text!.count <= 9
        }
        return true
    }
7
Sai kumar Reddy

Swift

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

            let nsString = NSString(string: textField.text!)
            let newText = nsString.replacingCharacters(in: range, with: string)
            return  newText.characters.count <= limitCount
    }
6
Basil Mariano

Si vous voulez écraser la dernière lettre:

let maxLength = 10

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

    if range.location > maxLength - 1 {
        textField.text?.removeLast()
    }

    return true
}
5
maxwell

J'ai posté une solution en utilisant IBInspectable, afin que vous puissiez modifier la valeur de longueur maximale à la fois dans le générateur d'interface ou par programme. Check it out here

4
frouo
Here is my version of code. Hope it helps!

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        let invalidCharacters = NSCharacterSet(charactersInString: "0123456789").invertedSet

        if let range = string.rangeOfCharacterFromSet(invalidCharacters, options: nil, range:Range<String.Index>(start: string.startIndex, end: string.endIndex))
        {
            return false
        }

        if (count(textField.text) > 10  && range.length == 0)
        {
            self.view.makeToast(message: "Amount entry is limited to ten digits", duration: 0.5, position: HRToastPositionCenter)
            return false
        }
        else
        {

        }

        return true
    }
1
A.G

Puisque les délégués forment une relation un-à-un et que je pourrais l'utiliser ailleurs pour d'autres raisons, j'aime limiter la longueur du champ de texte en ajoutant ce code dans leur configuration:

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        setup()
    }

    required override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    func setup() {

        // your setup...

        setMaxLength()
    }

    let maxLength = 10

    private func setMaxLength() {
            addTarget(self, action: #selector(textfieldChanged(_:)), for: UIControlEvents.editingChanged)
        }

        @objc private func textfieldChanged(_ textField: UITextField) {
            guard let text = text else { return }
            let trimmed = text.characters.prefix(maxLength)
            self.text = String(trimmed)

        }
1
MQLN

J'utilise ce protocole/cette extension dans l'une de mes applications et il est un peu plus lisible. J'aime la façon dont il reconnaît les espaces arrières et vous indique explicitement quand un personnage est un espace arrière.

Quelques points à considérer:

1.Quel que soit le type d'implémentation que cette extension de protocole nécessite de spécifier une limite de caractères. par exemple une limite de caractères sur l'un de vos modèles.

2. Vous devrez appeler cette méthode à l'intérieur de la méthode de délégation shouldChangeCharactersInRange de votre champ de texte. Sinon, vous ne pourrez pas bloquer la saisie de texte en renvoyant la valeur false, etc.

3. Vous voudrez probablement autoriser les caractères de retour arrière. C'est pourquoi j'ai ajouté la fonction supplémentaire permettant de détecter les espaces de retour. Votre méthode shouldChangeCharacters peut vérifier cela et renvoyer "true" au début afin de toujours autoriser les espaces de retour.

protocol TextEntryCharacterLimited{
    var characterLimit:Int { get } 
}

extension TextEntryCharacterLimited{

    func charactersInTextField(textField:UITextField, willNotExceedCharacterLimitWithReplacementString string:String, range:NSRange) -> Bool{

        let startingLength = textField.text?.characters.count ?? 0
        let lengthToAdd = string.characters.count
        let lengthToReplace = range.length

        let newLength = startingLength + lengthToAdd - lengthToReplace

        return newLength <= characterLimit

    }

    func stringIsBackspaceWith(string:String, inRange range:NSRange) -> Bool{
        if range.length == 1 && string.characters.count == 0 { return true }
        return false
    }

}

Si certains d'entre vous sont intéressés, j'ai un référentiel Github dans lequel j'ai pris un peu de ce comportement de limite de caractères et l'ai placé dans un cadre iOS. Il existe un protocole que vous pouvez implémenter pour obtenir un affichage de limite de caractères similaire à celui de Twitter qui indique jusqu'à quel point vous avez dépassé la limite de caractères.

CharacterLimited Framework sur Github

1
Theo Bendixson

Méfiez-vous du bogue d'annulation pour UITextField mentionné dans ce message: définir la longueur maximale de caractères d'un UITextField

voici comment résoudre ce problème dans Swift

if(range.length + range.location > count(textField.text)) {
        return false;
}
1
Horatio