Longueur maximale UITextField

120

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

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 je peux utiliser le retour arrière)?

Giorgio Nocera
la source

Réponses:

295

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

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 textFields smartInsertDeleteTypesur UITextSmartInsertDeleteType.no. Cela empêchera l'insertion possible d'un espace supplémentaire (indésirable) lors de l'exécution 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
    }

}
Imanou Petit
la source
Mettez-vous simplement ce code dans votre classe de contrôleur de vue? Ou dois-je établir des liens?
Isaac Wasserman
Si quelqu'un a besoin de mettre une condition .. vous pouvez faire comme ça ... if (textField .isEqual (mobileNumberTextfield)) {guard let text = textField.text else {return true} let newLength = text.characters.count + string.characters.count - range.length return newLength <= limitLength; } return true;
Narasimha Nallamsetty
6
Pour Swift 4, l' text.characters.countutilisation est déconseilléetext.count
Mohamed Salah
47

Je fais ça 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 lors de l' édition modifiée .

Martin
la source
1
countElements a été changé pour compter dans Swift 2, mais changer cela fonctionne pour moi!
John
1
Merci, vous pouvez utiliser maintenant textField.text? .Characters.count puisque countElements a été modifié.
Anibal R.
1
Tks, cela a très bien fonctionné avec ce changement: countElements (textField.text!) Dans Swift 2 est: textField.text? .Characters.count
kha
33

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
}
Shan Ye
la source
15

Ajoutez plus de détails à partir 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()
    }
}
Sruit A.Suk
la source
1
count (textField.text!) donne une erreur. Vous devez utiliser textField.text! .Characters.count
Regis St-Gelais
1
Merci @ RegisSt-Gelais, C'est déjà une vieille réponse, je l'ai mise à jour maintenant
Sruit A.Suk
11

Dans Swift 4

Limite de 10 caractères pour le champ de texte et autoriser 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
    }
Sai kumar Reddy
la source
8
func checkMaxLength(textField: UITextField!, maxLength: Int) {
        if (textField.text!.characters.count > maxLength) {
            textField.deleteBackward()
        }
}

un petit changement pour IOS 9

Jeremy Andrews
la source
8

Swift 3

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
    }
Basil Mariano
la source
8

vous pouvez étendre UITextField et ajouter un @IBInspectableobjet pour le gérer:

SWIFT 5

import UIKit
private var __maxLengths = [UITextField: Int]()
extension UITextField {
    @IBInspectable var maxLength: Int {
        get {
            guard let l = __maxLengths[self] else {
                return 150 // (global default-limit. or just, Int.max)
            }
            return l
        }
        set {
            __maxLengths[self] = newValue
            addTarget(self, action: #selector(fix), for: .editingChanged)
        }
    }
    @objc func fix(textField: UITextField) {
        if let t = textField.text {
            textField.text = String(t.prefix(maxLength))
        }
    }
}

et après cela définissez-le sur l'inspecteur d'attributs

entrez la description de l'image ici

Voir la réponse originale de Swift 4

Mohsen
la source
2
Beau code propre. Mais pour une raison quelconque, cela provoque un comportement d'édition étrange lorsque vous utilisez des emojis. Le curseur passe à la fin de la ligne chaque fois que vous essayez de modifier.
Phontaine Judd
5

Si vous souhaitez é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
}
Maxwell
la source
4

J'ai publié une solution à l'aide de IBInspectable, afin que vous puissiez modifier la valeur de longueur maximale à la fois dans le générateur d'interface ou par programme. Vérifiez le ici

frouo
la source
3

Vous pouvez utiliser dans swift 5 ou swift 4 comme l' image ci-dessous entrez la description de l'image ici

  1. Ajouter textField dans View Controller
  2. Connectez-vous au texte à ViewController
  3. ajouter le code dans la vue ViewController

     class ViewController: UIViewController , UITextFieldDelegate {
    
      @IBOutlet weak var txtName: UITextField!
    
      var maxLen:Int = 8;
    
     override func viewDidLoad() {
        super.viewDidLoad()
    
        txtName.delegate = self
       }
    
     func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
         if(textField == txtName){
            let currentText = textField.text! + string
            return currentText.count <= maxLen
         }
    
         return true;
       }
    }

Vous pouvez télécharger le formulaire source complet GitHub: https://github.com/enamul95/TextFieldMaxLen

Enamul Haque
la source
1

Méfiez-vous du bogue d'annulation pour UITextField mentionné dans cet article: Définissez la longueur de caractère maximale d'un UITextField

voici comment résoudre le problème rapidement

if(range.length + range.location > count(textField.text)) {
        return false;
}
Horatio
la source
Si vous souhaitez prendre en charge les emojis et autres, utilisez: if (range.length + range.location> count (textField.text.utf16)) {return false; }
AlexD
1
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
    }
AG
la source
1
J'aime l'extension Toast UIView :)
Regis St-Gelais
1

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

Quelques points à considérer:

Tout ce qui implémente cette extension de protocole doit spécifier une limite de caractères. Ce sera généralement votre ViewController, mais vous pouvez implémenter une limite de caractères en tant que propriété calculée et renvoyer quelque chose d'autre, 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égué shouldChangeCharactersInRange de votre champ de texte. Sinon, vous ne pourrez pas bloquer la saisie de texte en renvoyant false, etc.

3. Vous souhaiterez probablement autoriser les caractères de retour arrière. C'est pourquoi j'ai ajouté la fonction supplémentaire pour détecter les backspaces. Votre méthode shouldChangeCharacters peut vérifier cela et renvoyer «true» dès le début afin que vous autorisiez toujours les espaces arrière.

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 l'un d'entre vous est intéressé, j'ai un repo Github dans lequel j'ai pris une partie de ce comportement de limite de caractère et mis dans un cadre iOS. Il existe un protocole que vous pouvez implémenter pour obtenir un affichage de la limite de caractères de type Twitter qui vous montre jusqu'où vous êtes allé au-dessus de la limite de caractères.

CharacterLimited Framework sur Github

Théo Bendixson
la source
1

Puisque les délégués sont une relation 1 à 1 et que je pourrais vouloir 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)

        }
MQLN
la source
0

Im en utilisant ceci;

Limite de 3 caractères

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

        if let txt = textField.text {
            let currentText = txt + string
            if currentText.count > 3 {
                return false
            }
            return true
        }
        return true
    }
alicanozkara
la source
0

Swift 5

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let MAX_LENGTH = 4
        let updatedString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
        return updatedString.count <= MAX_LENGTH
    }
TDK
la source
-3

Vous devez vérifier si la chaîne existante plus l'entrée est supérieure à 10.

   func textField(textField: UITextField!,shouldChangeCharactersInRange range: NSRange,    replacementString string: String!) -> Bool {
      NSUInteger newLength = textField.text.length + string.length - range.length;
      return !(newLength > 10)
   }
bhzag
la source
5
Votre code est faux. 1. Vous devez déclarer votre constante ou variable avec let ou var dans Swift (pas NSUInteger). 2. textField.text et string sont de type String. La longueur n'est pas une propriété / méthode de String dans Swift.
Imanou Petit