Définir la longueur maximale de caractères d'un UITextField

Réponses:

1029

Bien que la UITextFieldclasse n'ait pas de propriété de longueur maximale, il est relativement simple d'obtenir cette fonctionnalité en définissant les champs de texte delegateet en implémentant la méthode déléguée suivante:

Objectif c

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    // Prevent crashing undo bug – see note below.
    if(range.length + range.location > textField.text.length)
    {
        return NO;
    }

    NSUInteger newLength = [textField.text length] + [string length] - range.length;
    return newLength <= 25;
}

Rapide

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

    let currentCharacterCount = textField.text?.count ?? 0
    if range.length + range.location > currentCharacterCount {
        return false
    }
    let newLength = currentCharacterCount + string.count - range.length
    return newLength <= 25
}

Avant que le champ de texte ne change, l'UITextField demande au délégué si le texte spécifié doit être modifié. Le champ de texte n'a pas changé à ce stade, nous prenons donc sa longueur actuelle et la longueur de chaîne que nous insérons (soit en collant du texte copié ou en tapant un seul caractère à l'aide du clavier), moins la longueur de la plage. Si cette valeur est trop longue (plus de 25 caractères dans cet exemple), revenez NOpour interdire la modification.

Lorsque vous saisissez un seul caractère à la fin d'un champ de texte, le range.locationsera la longueur du champ actuel et range.lengthsera 0 car nous ne remplaçons / supprimons rien. L'insertion au milieu d'un champ de texte signifie simplement une différence range.location, et le collage de plusieurs caractères signifie simplement qu'il y stringa plus d'un caractère.

La suppression de caractères uniques ou la découpe de plusieurs caractères est spécifiée par un rangeavec une longueur non nulle et une chaîne vide. Le remplacement est simplement une suppression de plage avec une chaîne non vide.

Une note sur le bug "d'annulation" qui plante

Comme mentionné dans les commentaires, il y a un bug UITextFieldqui peut conduire à un crash.

Si vous collez dans le champ, mais que le collage est empêché par votre implémentation de validation, l'opération de collage est toujours enregistrée dans le tampon d'annulation de l'application. Si vous déclenchez ensuite une annulation (en secouant l'appareil et en confirmant une annulation), le UITextFieldtentera de remplacer la chaîne qu'il pense qu'elle s'est collée à elle-même par une chaîne vide. Cela se bloque parce qu'il n'a jamais fait coller la chaîne pour lui - même. Il essaiera de remplacer une partie de la chaîne qui n'existe pas.

Heureusement, vous pouvez protéger le UITextFieldde se tuer comme ça. Vous avez juste besoin de faire en sorte que la gamme qu'il propose de remplacer ne exist dans son chaîne actuelle. C'est ce que fait le premier contrôle d'esprit ci-dessus.

swift 3.0 avec copier-coller fonctionne bien.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let str = (textView.text + text)
        if str.characters.count <= 10 {
            return true
        }
        textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
        return false
    }

J'espère que cela vous sera utile.

malade
la source
7
Trouvé une solution en entourant ces 2 lignes avec if (textField == _ssn) {} et en ajoutant return YES; à la fin de la méthode, ce qui permettra à tous les autres UITextFields d'accepter du texte sans aucune restriction. Nifty!
Kyle Clegg
55
Bonne réponse, mais l'opérateur ternaire est superflu; vous pourriez simplement mettrereturn newLength <= 25;
jowie
2
Et si vous voulez juste que le texte ne déborde pas du cadre du champ de texte; tous les caractères n'ont pas la même largeur, non?
Morkrom du
2
Il y a vraiment un bug d'annulation comme le mentionne @bcherry - testé avec UITextFieldsur iPad iOS 8.1. (+1 pour commenter). L'auteur ajouterait-il quelque chose à ce sujet car c'est la réponse la mieux notée? Je suis heureux de faire un montage, mais le mien semble régulièrement rejeté! :-)
Benjohn
8
@bherry Dans Swift, la vérification du cas d'annulation semble casser l'entrée des emoji. Le compte (textField.text) ne devrait-il pas réellement être count (textField.text.utf16) pour correspondre au rapport objc / uikit dans la plage (vs la variante de Swift du compte sur les chaînes)?
rcw3
62

Swift 4

import UIKit

private var kAssociationKeyMaxLength: Int = 0

extension UITextField {

    @IBInspectable var maxLength: Int {
        get {
            if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                return length
            } else {
                return Int.max
            }
        }
        set {
            objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
            addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
        }
    }

    @objc func checkMaxLength(textField: UITextField) {
        guard let prospectiveText = self.text,
            prospectiveText.count > maxLength
            else {
                return
        }

        let selection = selectedTextRange

        let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
        let substring = prospectiveText[..<indexEndOfText]
        text = String(substring)

        selectedTextRange = selection
    }
}

Edit: problème de fuite de mémoire corrigé.

entrez la description de l'image ici

frouo
la source
Excellente idée Frouo! Je l'ai développé dans ma réponse pour déplacer le découpage maxLength vers une extension String afin qu'il puisse également être utilisé pour des choses comme les instances UITextView, et pour ajouter une fonction pratique pour tirer parti de ces extensions String dans une extension UITextField.
Scott Gardner
1
Cette variable globale ne crée-t-elle pas des fuites de mémoire, en conservant des références à toutes les vues de texte (qui font référence aux superviews jusqu'à root-)
Ixx
3
@Ixx J'ai édité pour corriger le problème de fuite de mémoire que vous avez signalé + rapide 3. Merci
frouo
1
la plus belle façon de l'atteindre! Merci
Victor Choy
quelqu'un peut-il me fournir sa version objective
MRizwan33
56

Merci août! ( Message )

Voici le code avec lequel j'ai fini et qui fonctionne:

#define MAX_LENGTH 20

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField.text.length >= MAX_LENGTH && range.length == 0)
    {
        return NO; // return NO to not change text
    }
    else
    {return YES;}
}
Domness
la source
19
Malheureusement, cette solution ne parvient pas à empêcher les utilisateurs de copier-coller dans un champ de texte, leur permettant ainsi de contourner la limite. La réponse de Sickpea résout correctement cette situation.
Ant
5
Qu'en est-il des personnes ayant une déclaration if pour retourner NON ou OUI? Essayez ceci: return! (TextField.text.length> = MAX_LENGTH && range.length == 0);
Matt Parkins du
ou cecireturn textField.text.length < MAX_LENGTH || range.length != 0;
igrek
22

Pour compléter la réponse du mois d'août , une implémentation possible de la fonction proposée (voir délégué UITextField ).

Je n'ai pas testé le code domness , mais le mien ne se bloque pas si l'utilisateur atteint la limite, et il est compatible avec une nouvelle chaîne qui vient remplacer une plus petite ou égale.

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    //limit the size :
    int limit = 20;
    return !([textField.text length]>limit && [string length] > range.length);
}
Jmini
la source
17

Vous ne pouvez pas le faire directement - UITextFieldn'a pas d' attribut maxLength , mais vous pouvez définir le UITextField'sdélégué, puis utiliser:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
août
la source
5
Je suis d'accord, c'est la meilleure façon d'avancer, mais cela reste un peu un hack. Soumettez un rapport de bogue à Apple que vous souhaitez voir une propriété pour la longueur du texte. Cela m'intéresse certainement aussi.
avocat le
5
@avocade, ce n'est pas un hack: c'est un exemple où vous devez faire du code cadre de base qu'Apple aurait dû faire pour vous. Il existe de nombreux exemples de cela dans le SDK iOS.
Dan Rosenstark
13

Vous disposez souvent de plusieurs champs de saisie de longueur différente.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    int allowedLength;
    switch(textField.tag) {
        case 1: 
            allowedLength = MAXLENGTHNAME;      // triggered for input fields with tag = 1
            break;
        case 2:
            allowedLength = MAXLENGTHADDRESS;   // triggered for input fields with tag = 2
            break;
        default:
            allowedLength = MAXLENGTHDEFAULT;   // length default when no tag (=0) value =255
            break;
    }

    if (textField.text.length >= allowedLength && range.length == 0) {
        return NO; // Change not allowed
    } else {
        return YES; // Change allowed
    }
}
Vincent
la source
12

La meilleure façon serait de mettre en place une notification sur le changement de texte. Dans votre -awakeFromNibméthode de contrôleur de vue, vous souhaiterez:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(limitTextField:) name:@"UITextFieldTextDidChangeNotification" object:myTextField];

Ensuite, dans la même classe, ajoutez:

- (void)limitTextField:(NSNotification *)note {
    int limit = 20;
    if ([[myTextField stringValue] length] > limit) {
        [myTextField setStringValue:[[myTextField stringValue] substringToIndex:limit]];
    }
}

Reliez ensuite la prise myTextFieldà votre UITextFieldet il ne vous permettra plus d'ajouter de personnages après avoir atteint la limite. Assurez-vous d'ajouter ceci à votre méthode de désallocation:

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UITextFieldTextDidChangeNotification" object:myTextField];
Martin Pilkington
la source
Bien que j'aie fait cela pour supprimer les erreurs> myTextField.text = [myTextField.text substringToIndex: limit];
Luke
11

J'ai créé cette sous-classe UITextFieldLimit:

  • Plusieurs champs de texte pris en charge
  • Définir la longueur maximale du texte
  • Prévention du collage
  • Affiche une étiquette de caractères à gauche à l'intérieur du champ de texte, cachez-vous lorsque vous arrêtez l'édition.
  • Secouez l'animation quand il ne reste aucun personnage.

Saisissez le UITextFieldLimit.het à UITextFieldLimit.mpartir de ce référentiel GitHub:

https://github.com/JonathanGurebo/UITextFieldLimit

et commencez à tester!

Marquez votre UITextField créé par le storyboard et liez-le à ma sous-classe à l'aide de l'inspecteur d'identité:

Inspecteur d'identité

Vous pouvez ensuite le lier à un IBOutlet et définir la limite (la valeur par défaut est 10).


Votre fichier ViewController.h doit contenir: (si vous ne souhaitez pas modifier le paramètre, comme la limite)

#import "UITextFieldLimit.h"

/.../

@property (weak, nonatomic) IBOutlet UITextFieldLimit *textFieldLimit; // <--Your IBOutlet

Votre fichier ViewController.m devrait @synthesize textFieldLimit.


Définissez la limite de longueur du texte dans votre fichier ViewController.m:

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

    [textFieldLimit setLimit:25];// <-- and you won't be able to put more than 25 characters in the TextField.
}

J'espère que la classe vous aidera. Bonne chance!

Jonathan Gurebo
la source
Pour le petit besoin de la limite de caractères, je pense que l'ajout de votre classe serait juste exagéré.
Domness
Encore un effort apprécié.
Reaper
11

Cela devrait suffire à résoudre le problème (remplacez 4 par la limite que vous voulez). Assurez-vous simplement d'ajouter un délégué dans IB.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
     NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
     return (newString.length<=4);
}
Nishant
la source
9

Utilisez l'extension ci-dessous pour définir la longueur maximale des caractères de a UITextFieldet UITextView.

Swift 4.0

    private var kAssociationKeyMaxLength: Int = 0
    private var kAssociationKeyMaxLengthTextView: Int = 0
    extension UITextField {


        @IBInspectable var maxLength: Int {
            get {
                if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                    return length
                } else {
                    return Int.max
                }
            }
            set {
                objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
                addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
            }
        }

        @objc func checkMaxLength(textField: UITextField) {
            guard let prospectiveText = self.text,
                prospectiveText.count > maxLength
                else {
                    return
            }

            let selection = selectedTextRange

            let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
            let substring = prospectiveText[..<indexEndOfText]
            text = String(substring)

            selectedTextRange = selection
        }
    }

UITextView

extension UITextView:UITextViewDelegate {


        @IBInspectable var maxLength: Int {
            get {
                if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLengthTextView) as? Int {
                    return length
                } else {
                    return Int.max
                }
            }
            set {
                self.delegate = self

                objc_setAssociatedObject(self, &kAssociationKeyMaxLengthTextView, newValue, .OBJC_ASSOCIATION_RETAIN)
            }
        }

        public func textViewDidChange(_ textView: UITextView) {
            checkMaxLength(textField: self)
        }
        @objc func checkMaxLength(textField: UITextView) {
            guard let prospectiveText = self.text,
                prospectiveText.count > maxLength
                else {
                    return
            }

            let selection = selectedTextRange

            let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
            let substring = prospectiveText[..<indexEndOfText]
            text = String(substring)

            selectedTextRange = selection
        }
    }

Vous pouvez définir une limite ci-dessous.

entrez la description de l'image ici

COVID-19 [FEMININE
la source
meilleure réponse de loin ,,, merci beaucoup d'une excellente solution quand il y a beaucoup de champs de texte qui nécessitent des longueurs différentes
Carlos Norena
Vraiment une excellente solution pour la limite d'entrée de caractères de contrôle de champ de texte et de visualisation de texte. Ses lignes de code de sauvegarde et le temps aussi pour le développeur ... :)
Sandip Patel - SM
Cela fonctionne mieux que les autres solutions que j'ai trouvées. Par exemple, si vous avez des emojis dans votre champ de texte, d'autres extensions que j'ai trouvées passeraient à la fin de la ligne lors de l'édition. Mais votre code ne fait pas ça. Merci!
Phontaine Judd
7

Je simule le remplacement de chaîne réel qui est sur le point de se produire pour calculer la longueur de cette future chaîne:

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

    NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if([newString length] > maxLength)
       return NO;

    return YES;
}
samvermette
la source
7

Version Swift 3 // ***** Cela ne fonctionnera PAS avec Swift 2.x! ***** //

Créez d'abord un nouveau fichier Swift: TextFieldMaxLength.swift, puis ajoutez le code ci-dessous:

import UIKit

private var maxLengths = [UITextField: Int]()

extension UITextField {

   @IBInspectable var maxLength: Int {

      get {

          guard let length = maxLengths[self] 
             else {
                return Int.max
      }
      return length
   }
   set {
      maxLengths[self] = newValue
      addTarget(
         self,
         action: #selector(limitLength),
         for: UIControlEvents.editingChanged
      )
   }
}
func limitLength(textField: UITextField) {
    guard let prospectiveText = textField.text,
        prospectiveText.characters.count > maxLength
    else {
        return
    }

   let selection = selectedTextRange
   let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
   text = prospectiveText.substring(to: maxCharIndex)
   selectedTextRange = selection
   }
}

puis vous verrez dans Storyboard un nouveau champ (longueur maximale) lorsque vous sélectionnez un TextField

Si vous avez encore des questions, consultez ce lien: http://www.globalnerdy.com/2016/05/18/ios-programming-trick-how-to-use-xcode-to-set-a-text-fields -style visuel-studio-longueur maximale /

Gilad Brunfman
la source
Attention, cette variable globale crée des fuites de mémoire, en contenant des références à toutes les vues de texte.
frouo
6

En utilisant le générateur d'interface, vous pouvez lier et obtenir l'événement pour "Modification modifiée" dans n'importe laquelle de vos fonctions. Maintenant, vous pouvez vérifier la longueur

- (IBAction)onValueChange:(id)sender 
{
    NSString *text = nil;
    int MAX_LENGTH = 20;
    switch ([sender tag] ) 
    {
        case 1: 
        {
            text = myEditField.text;
            if (MAX_LENGTH < [text length]) {
                myEditField.text = [text substringToIndex:MAX_LENGTH];
            }
        }
            break;
        default:
            break;
    }

}
Vishal Kumar
la source
6

Le code suivant est similaire à la réponse de malade, mais gère correctement les opérations de copier-coller. Si vous essayez de coller un texte plus long que la limite, le code suivant tronquera le texte pour qu'il corresponde à la limite au lieu de refuser complètement l'opération de collage.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    static const NSUInteger limit = 70; // we limit to 70 characters
    NSUInteger allowedLength = limit - [textField.text length] + range.length;
    if (string.length > allowedLength) {
        if (string.length > 1) {
            // get at least the part of the new string that fits
            NSString *limitedString = [string substringToIndex:allowedLength];
            NSMutableString *newString = [textField.text mutableCopy];
            [newString replaceCharactersInRange:range withString:limitedString];
            textField.text = newString;
        }
        return NO;
    } else {
        return YES;
    }
}
Wroluk
la source
6

Il existe une solution générique pour définir la longueur maximale dans Swift. Par IBInspectable, vous pouvez ajouter un nouvel attribut dans Xcode Attribute Inspector.entrez la description de l'image ici

import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {

    @IBInspectable var maxLength: Int {
        get {
            guard let length = maxLengths[self]
            else {
                return Int.max
            }
            return length
        }
        set {
            maxLengths[self] = newValue
            addTarget(
                self,
                action: Selector("limitLength:"),
                forControlEvents: UIControlEvents.EditingChanged
            )
        }
    }

    func limitLength(textField: UITextField) {
        guard let prospectiveText = textField.text
            where prospectiveText.characters.count > maxLength else {
                return
        }
        let selection = selectedTextRange
        text = prospectiveText.substringWithRange(
            Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength))
        )
        selectedTextRange = selection
    }

}
Hiren
la source
Solution propre et parfaite
Eduardo
Tenir un UITextField dans un champ global les conservera dans la mémoire même après que l'UIViewController aura été fermé. Il s'agit d'une fuite de mémoire. N'utilisez pas cette méthode.
Gunhan
5

Pour le faire fonctionner avec un copier-coller de chaînes de n'importe quelle longueur, je suggère de changer la fonction en quelque chose comme:

#define MAX_LENGTH 20

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        NSInteger insertDelta = string.length - range.length;

        if (textField.text.length + insertDelta > MAX_LENGTH)
        {
           return NO; // the new string would be longer than MAX_LENGTH
        }
        else {
            return YES;
        }
    }
Påhl Melin
la source
4

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
Pourquoi guard?
oddRaven
vérifiez si le texte est nul, si vous le souhaitez, vous pouvez également utiliser si @oddRaven
Shan Ye
3

Swift 2.0 +

Créez d'abord une classe pour ce processus. Appelons-le StringValidator.swift.

Ensuite, collez simplement le code suivant à l'intérieur.

import Foundation

extension String {

func containsCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) != nil
}

func containsOnlyCharactersIn(matchCharacters: String) -> Bool {
let disallowedCharacterSet = NSCharacterSet(charactersInString: matchCharacters).invertedSet
return self.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
}


func doesNotContainCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) == nil
}

func isNumeric() -> Bool
{
let scanner = NSScanner(string: self)
scanner.locale = NSLocale.currentLocale()

return scanner.scanDecimal(nil) && scanner.atEnd
}

}

Maintenant, sauvez la classe .....

Usage..

Maintenant, passez à votre classe viewController.swift et définissez les sorties de votre champ de texte comme ..

@IBOutlet weak var contactEntryTxtFld: UITextField! //First textfield
@IBOutlet weak var contactEntryTxtFld2: UITextField!   //Second textfield

Maintenant, passez à la méthode shouldChangeCharactersInRange du champ de texte et utilisez comme suit.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if string.characters.count == 0 {
        return true
    }
    let latestText = textField.text ?? ""
    let checkAbleText = (latestText as NSString).stringByReplacingCharactersInRange(range, withString: string)


    switch textField {

    case contactEntryTxtFld:
        return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5

    case contactEntryTxtFld2:
        return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5

    default:
        return true
    }

}

N'oubliez pas de définir le protocole délégué / les méthodes des champs de texte.

Permettez-moi de vous expliquer à ce sujet ... J'utilise le processus d'extension simple de chaîne que j'ai écrit dans une autre classe. Maintenant, j'appelle simplement ces méthodes d'extension à partir d'une autre classe où j'en ai besoin en ajoutant une vérification et une valeur maximale.

Caractéristiques...

  1. Il fixera la limite maximale d'un champ de texte particulier.
  2. Il définira le type de clés acceptées pour un champ de texte particulier.

Les types...

containsOnlyCharactersIn // Accepte uniquement les caractères.

containsCharactersIn // Accepte une combinaison de caractères

doesNotContainsCharactersIn // N'accepte pas les caractères

J'espère que cela a aidé .... Merci ..

en complément
la source
3

swift 3.0

Ce code fonctionne correctement lorsque vous collez une chaîne plus que vos limites de caractères.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let str = (textView.text + text)
        if str.characters.count <= 10 {
            return true
        }
        textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
        return false
    }

Merci pour vos votes. :)

Ilesh P
la source
2
UITextField, pas UITextView.
Jonny
3

Je donne une réponse supplémentaire basée sur @Frouo. Je pense que sa réponse est la plus belle manière. Parce que c'est un contrôle commun que nous pouvons réutiliser.

private var kAssociationKeyMaxLength: Int = 0

extension UITextField {

    @IBInspectable var maxLength: Int {
        get {
            if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                return length
            } else {
                return Int.max
            }
        }
        set {
            objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
            self.addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
        }
    }

    func checkMaxLength(textField: UITextField) {

        guard !self.isInputMethod(), let prospectiveText = self.text,
            prospectiveText.count > maxLength
            else {
                return
        }

        let selection = selectedTextRange
        let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
        text = prospectiveText.substring(to: maxCharIndex)
        selectedTextRange = selection
    }

    //The method is used to cancel the check when use Chinese Pinyin input method.
    //Becuase the alphabet also appears in the textfield when inputting, we should cancel the check.
    func isInputMethod() -> Bool {
        if let positionRange = self.markedTextRange {
            if let _ = self.position(from: positionRange.start, offset: 0) {
                return true
            }
        }
        return false
    }

}
Victor Choy
la source
2

C'est la bonne façon de gérer la longueur maximale sur UITextField, cela permet à la touche de retour de quitter le champ de texte en tant que premier répondeur et permet à l'utilisateur de revenir en arrière lorsqu'ils atteignent la limite

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
int MAX_LENGHT = 5;
    if([string isEqualToString:@"\n"])
    {
        [textField resignFirstResponder];
        return FALSE;
    }
    else if(textField.text.length > MAX_LENGHT-1)
    {
        if([string isEqualToString:@""] && range.length == 1)
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    else
    {
        return TRUE;
    }
}
anders
la source
2

Qu'en est-il de cette approche simple. Cela fonctionne bien pour moi.

extension UITextField {

    func  charactersLimit(to:Int) {

        if (self.text!.count > to) {
            self.deleteBackward()
        }
    }
}

Alors:

someTextField.charactersLimit(to:16)
Joaquin Pereira
la source
1

D'autres réponses ne gèrent pas le cas où l'utilisateur peut coller une longue chaîne à partir du presse-papiers. Si je colle une longue chaîne, elle devrait simplement être tronquée mais affichée. Utilisez ceci dans votre délégué:

static const NSUInteger maxNoOfCharacters = 5;

-(IBAction)textdidChange:(UITextField * )textField
{
NSString * text = textField.text;

if(text.length > maxNoOfCharacters)
{
    text = [text substringWithRange:NSMakeRange(0, maxNoOfCharacters)];
    textField.text = text;
}

// use 'text'

}
8suhas
la source
1

Je l'ai réduit à 1 ligne de code :)

Définissez le délégué de votre affichage de texte sur "self" puis ajoutez le <UITextViewDelegate>dans votre .h et le code suivant dans votre .m .... vous pouvez ajuster le nombre "7" pour qu'il soit ce que vous voulez que votre nombre MAXIMUM de caractères soit.

-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
    return ((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length)>0);
}

Ce code prend en compte la saisie de nouveaux caractères, la suppression de caractères, la sélection de caractères, puis la saisie ou la suppression, la sélection de caractères et la découpe, le collage en général et la sélection de caractères et le collage.

Terminé!






Alternativement, une autre façon intéressante d'écrire ce code avec des opérations sur les bits serait

-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
    return 0^((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length));
}
Albert Renshaw
la source
1

J'ai ouvert une sous-classe UITextField, STATextField , qui offre cette fonctionnalité (et bien plus) avec sa maxCharacterLengthpropriété.

Stunner
la source
1

maintenant combien de caractères vous voulez juste donner des valeurs

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range   replacementString:(NSString *)string {
     NSUInteger newLength = [textField.text length] + [string length] - range.length;
     return (newLength > 25) ? NO : YES;
  }
chowdary mahesh
la source
1

Utilisez ce code ici RESTRICTED_LENGTH est la longueur que vous souhaitez restreindre pour le champ de texte.

   - (BOOL)textField:(UITextField *)textField     shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField == nameTF) {
    int limit = RESTRICTED_LENGTH - 1;
    return !([textField.text length]>limit && [string length] > range.length);
    }
   else
   {
    return YES;
   }

return NO;

}
Amit Shelgaonkar
la source
1

J'ai fait cela dans Swift pour une limite de 8 caractères lors de l'utilisation d'un pavé numérique.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return !(textField.text?.characters.count == MAX_LENGTH && string != "")
}

J'ai dû tester la chaîne! = "" Pour permettre au bouton de suppression de fonctionner sur le pavé numérique, sinon il ne permettrait pas de supprimer des caractères dans le champ de texte après avoir atteint son maximum.

u84six
la source
1

Pour Xamarin:

YourTextField.ShouldChangeCharacters = 
delegate(UITextField textField, NSRange range, string replacementString)
        {
            return (range.Location + replacementString.Length) <= 4; // MaxLength == 4
        };
Kedu
la source
1

J'ai implémenté une extension UITextField pour y ajouter une propriété maxLength.

Il est basé sur Xcode 6 IBInspectables, vous pouvez donc définir la limite maxLength sur le générateur d'interface.

Voici l'implémentation:

UITextField + MaxLength.h

#import <UIKit/UIKit.h>

@interface UITextField_MaxLength : UITextField<UITextFieldDelegate>

@property (nonatomic)IBInspectable int textMaxLength;
@end

UITextField + MaxLength.m

#import "UITextField+MaxLength.h"

@interface UITextField_MaxLength()

@property (nonatomic, assign) id <UITextFieldDelegate> superDelegate;

@end

@implementation UITextField_MaxLength

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

    //validate the length, only if it's set to a non zero value
    if (self.textMaxLength>0) {
        if(range.length + range.location > textField.text.length)
            return NO;

        if (textField.text.length+string.length - range.length>self.textMaxLength) {
            return NO;
        }
    }

    //if length validation was passed, query the super class to see if the delegate method is implemented there
    if (self.superDelegate && [self.superDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
        return [self.superDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
    }
    else{
        //if the super class does not implement the delegate method, simply return YES as the length validation was passed
        return YES;
    }
}

- (void)setDelegate:(id<UITextFieldDelegate>)delegate {
    if (delegate == self)
        return;
    self.superDelegate = delegate;
    [super setDelegate:self];
}

//forward all non overriden delegate methods
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([self.superDelegate  respondsToSelector:aSelector])
        return self.superDelegate;

    return [super forwardingTargetForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    if ([self.superDelegate respondsToSelector:aSelector])
        return YES;

    return [super respondsToSelector:aSelector];
}
@end
Lefteris
la source