Maximale Länge UITextField

120

Wenn ich versucht habe, wie Sie die maximale Anzahl von Zeichen festlegen, die mit Swift in ein UITextField eingegeben werden können? Ich habe gesehen, dass ich das Zeichen auch nicht löschen kann, wenn ich alle 10 Zeichen verwende.

Das einzige, was ich tun kann, ist, den Vorgang abzubrechen (alle Zeichen zusammen löschen).

Weiß jemand, wie man die Tastatur nicht blockiert (damit ich keine anderen Buchstaben / Symbole / Zahlen hinzufügen kann, aber die Rücktaste verwenden kann)?

Giorgio Nocera
quelle

Antworten:

294

Versuchen Sie unter Swift 5 und iOS 12 die folgende Implementierung einer textField(_:shouldChangeCharactersIn:replacementString:)Methode, die Teil des UITextFieldDelegateProtokolls ist:

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
}
  • Der wichtigste Teil dieses Codes ist die Konvertierung von range( NSRange) nach rangeOfTextToReplace( Range<String.Index>). In diesem Video-Tutorial erfahren Sie , warum diese Konvertierung wichtig ist.
  • Damit dieser Code ordnungsgemäß funktioniert, sollten Sie auch den Wert von textField' smartInsertDeleteTypeauf setzen UITextSmartInsertDeleteType.no. Dies verhindert das mögliche Einfügen eines (unerwünschten) zusätzlichen Speicherplatzes beim Ausführen eines Einfügevorgangs.

Der komplette Beispielcode unten zeigt , wie zur Umsetzung textField(_:shouldChangeCharactersIn:replacementString:)in ein 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
quelle
Fügen Sie diesen Code einfach in Ihre View Controller-Klasse ein? Oder muss ich Verbindungen herstellen?
Isaac Wasserman
Wenn jemand eine Bedingung stellen muss, können Sie dies tun. 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
5
Für Swift 4 text.characters.countist die Verwendung veraltettext.count
Mohamed Salah
47

So mach ich es:

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

Der Code funktioniert bei mir. Aber ich arbeite mit Storyboard. Im Storyboard füge ich beim Bearbeiten eine Aktion für das Textfeld im View Controller hinzu .

Martin
quelle
1
countElements wurde geändert, um in Swift 2 zu zählen, aber das zu ändern funktioniert für mich!
John
1
Vielen Dank, Sie können jetzt textField.text? .Characters.count verwenden, da countElements geändert wurde.
Anibal R.
1
Tks, es hat großartig mit dieser Änderung funktioniert: countElements (textField.text!) In Swift 2 ist: textField.text? .Characters.count
kha
32

Update für 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
quelle
15

Weitere Details aus der @ Martin-Antwort hinzufügen

// 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()
    }
}
Obst A.Suk
quelle
1
count (textField.text!) gibt einen Fehler aus. Sie müssen textField.text! .Characters.count
Regis St-Gelais
1
Danke @ RegisSt-Gelais, Es ist bereits eine alte Antwort, ich habe sie jetzt aktualisiert
Sruit A.Suk
11

In Swift 4

10 Zeichen begrenzen für Textfeld und erlauben das Löschen (Rücktaste)

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
quelle
8
func checkMaxLength(textField: UITextField!, maxLength: Int) {
        if (textField.text!.characters.count > maxLength) {
            textField.deleteBackward()
        }
}

eine kleine Änderung für IOS 9

Jeremy Andrews
quelle
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
quelle
7

Sie können UITextField erweitern und ein @IBInspectableObjekt hinzufügen, um es zu behandeln:

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))
        }
    }
}

und danach definieren Sie es im Attributinspektor

Geben Sie hier die Bildbeschreibung ein

Siehe Swift 4 Originalantwort

Mohsen
quelle
2
Schöner, sauberer Code. Aus irgendeinem Grund führt dies jedoch zu einem seltsamen Bearbeitungsverhalten, wenn Sie Emojis verwenden. Der Cursor springt bei jedem Versuch, ihn zu bearbeiten, zum Zeilenende.
Phontaine Judd
5

Wenn Sie den letzten Buchstaben überschreiben möchten:

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
quelle
4

Ich habe eine Lösung mit gepostet IBInspectable, sodass Sie den Wert für die maximale Länge sowohl im Interface Builder als auch programmgesteuert ändern können. Schau es dir hier an

frouo
quelle
3

Sie können in Swift 5 oder Swift 4 verwenden, wie das Bild wie unten aussieht Geben Sie hier die Bildbeschreibung ein

  1. Fügen Sie textField in View Controller hinzu
  2. Stellen Sie eine Verbindung zum Text zu ViewController her
  3. Fügen Sie den Code in der Ansicht ViewController hinzu

     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;
       }
    }

Sie können das vollständige Quellformular von GitHub herunterladen: https://github.com/enamul95/TextFieldMaxLen

Enamul Haque
quelle
1

Beachten Sie den in diesem Beitrag erwähnten Rückgängig-Fehler für UITextField: Legen Sie die maximale Zeichenlänge eines UITextField fest

Hier erfahren Sie, wie Sie das Problem schnell beheben

if(range.length + range.location > count(textField.text)) {
        return false;
}
Horatio
quelle
Wenn Sie Emoji und eine solche Verwendung unterstützen möchten: 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
quelle
1
Ich mag die Toast UIView Erweiterung :)
Regis St-Gelais
1

Ich habe dieses Protokoll / diese Erweiterung in einer meiner Apps verwendet und es ist etwas besser lesbar. Mir gefällt, wie es Backspaces erkennt und Ihnen explizit sagt, wann ein Zeichen ein Backspace ist.

Einige Dinge zu beachten:

1.Was auch immer diese Protokollerweiterung implementiert, muss eine Zeichenbeschränkung angeben. Dies ist normalerweise Ihr ViewController. Sie können jedoch die Zeichenbeschränkung als berechnete Eigenschaft implementieren und etwas anderes zurückgeben, z. B. eine Zeichenbeschränkung für eines Ihrer Modelle.

2. Sie müssen diese Methode innerhalb der delegierten Methode shouldChangeCharactersInRange Ihres Textfelds aufrufen. Andernfalls können Sie die Texteingabe nicht blockieren, indem Sie false usw. zurückgeben.

3. Sie möchten wahrscheinlich Rücktaste durchlassen. Aus diesem Grund habe ich die zusätzliche Funktion zum Erkennen von Backspaces hinzugefügt. Ihre shouldChangeCharacters-Methode kann dies überprüfen und frühzeitig 'true' zurückgeben, sodass Sie immer Backspaces zulassen.

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
    }

}

Wenn einer von Ihnen interessiert ist, habe ich ein Github-Repo, in dem ich einige dieser Zeichenbeschränkungsverhaltensweisen übernommen und in ein iOS-Framework integriert habe. Es gibt ein Protokoll, das Sie implementieren können, um eine Twitter-ähnliche Anzeige für die Zeichenbegrenzung zu erhalten, die anzeigt, wie weit Sie die Zeichenbegrenzung überschritten haben.

CharacterLimited Framework auf Github

Theo Bendixson
quelle
1

Da es sich bei den Delegierten um eine 1-zu-1-Beziehung handelt und ich sie aus anderen Gründen möglicherweise an anderer Stelle verwenden möchte, möchte ich die Länge des Textfelds einschränken und diesen Code in das Setup aufnehmen:

    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
quelle
0

Ich benutze das;

Limit 3 char

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
quelle
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
quelle
-3

Sie müssen überprüfen, ob die vorhandene Zeichenfolge plus die Eingabe größer als 10 ist.

   func textField(textField: UITextField!,shouldChangeCharactersInRange range: NSRange,    replacementString string: String!) -> Bool {
      NSUInteger newLength = textField.text.length + string.length - range.length;
      return !(newLength > 10)
   }
bhzag
quelle
5
Ihr Code ist falsch. 1. Sie müssen Ihre Konstante oder Variable mit let oder var in Swift deklarieren (nicht NSUInteger). 2. textField.text und string sind vom Typ String. Länge ist keine Eigenschaft / Methode von String in Swift.
Imanou Petit