Lunghezza massima UITextField


120

Quando ho provato Come impostare il numero massimo di caratteri che possono essere inseriti in un UITextField utilizzando swift? , Ho visto che se uso tutti e 10 i caratteri, non posso cancellare anche il carattere.

L'unica cosa che posso fare è annullare l'operazione (eliminare tutti i caratteri insieme).

Qualcuno sa come non bloccare la tastiera (così non posso aggiungere altre lettere / simboli / numeri, ma posso usare il backspace)?

Risposte:


295

Con Swift 5 e iOS 12, prova la seguente implementazione del textField(_:shouldChangeCharactersIn:replacementString:)metodo che fa parte del UITextFieldDelegateprotocollo:

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 parte più importante di questo codice è la conversione da range( NSRange) a rangeOfTextToReplace( Range<String.Index>). Guarda questo video tutorial per capire perché questa conversione è importante.
  • Per fare questo lavoro di codice correttamente, si dovrebbe anche impostare il textField's smartInsertDeleteTypevalore UITextSmartInsertDeleteType.no. Ciò impedirà il possibile inserimento di uno spazio aggiuntivo (indesiderato) durante l'esecuzione di un'operazione di incolla.

Il codice di esempio completo di seguito mostra come implementare textField(_:shouldChangeCharactersIn:replacementString:)in 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
    }

}

Metti semplicemente questo codice nella classe del controller di visualizzazione? O devo fare collegamenti?
Isaac Wasserman

Se qualcuno ha bisogno di mettere qualche condizione .. puoi fare così ... 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; } restituisce vero;
Narasimha Nallamsetty

6
Per Swift 4, l' text.characters.countuso è deprecatotext.count
Mohamed Salah

47

Lo faccio così:

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

Il codice funziona per me. Ma lavoro con lo storyboard. In Storyboard aggiungo un'azione per il campo di testo nel controller della vista durante la modifica modificata .


1
countElements è stato modificato per contare in Swift 2, ma cambiarlo funziona per me!
John

1
Grazie, ora puoi usare textField.text? .Characters.count poiché countElements è stato modificato.
Anibal R.

1
Tks, ha funzionato alla grande con questa modifica: countElements (textField.text!) In Swift 2 è: textField.text? .Characters.count
kha

33

Aggiornamento per 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
}

15

Aggiungi più dettagli dalla risposta di @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()
    }
}

1
count (textField.text!) restituisce un errore. Devi usare textField.text! .Characters.count
Regis St-Gelais

1
Grazie @ RegisSt-Gelais, è già una vecchia risposta, l'ho aggiornata ora
Sruit A.Suk

11

In Swift 4

Limite di 10 caratteri per il campo di testo e consente l'eliminazione (backspace)

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
    }

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

una piccola modifica per IOS 9


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
    }

8

puoi estendere UITextField e aggiungere un @IBInspectableoggetto per gestirlo:

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

e successivamente definiscilo nell'ispettore degli attributi

inserisci qui la descrizione dell'immagine

Vedi la risposta originale di Swift 4


2
Codice carino e pulito. Ma per qualche motivo questo provoca strani comportamenti di modifica quando usi gli emoji. Il cursore salta alla fine della riga ogni volta che provi a modificare.
Phontaine Judd

5

Se vuoi sovrascrivere l'ultima lettera:

let maxLength = 10

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

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

    return true
}

4

Ho pubblicato una soluzione usando IBInspectable, quindi puoi modificare il valore della lunghezza massima sia nel generatore di interfacce che a livello di programmazione. Controllalo qui


3

Puoi usare swift 5 o swift 4 come l' immagine qui sotto inserisci qui la descrizione dell'immagine

  1. Aggiungi textField in View Controller
  2. Connetti al testo a ViewController
  3. aggiungere il codice nella visualizzazione 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;
       }
    }

È possibile scaricare il modulo sorgente completo GitHub: https://github.com/enamul95/TextFieldMaxLen



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
    }

1
Mi piace l'estensione Toast UIView :)
Regis St-Gelais

1

Ho utilizzato questo protocollo / estensione in una delle mie app ed è un po 'più leggibile. Mi piace come riconosce i backspace e ti dice esplicitamente quando un carattere è un backspace.

Alcune cose da considerare:

1. Qualunque cosa implementi questa estensione del protocollo deve specificare un limite di caratteri. In genere sarà il tuo ViewController, ma potresti implementare il limite di caratteri come proprietà calcolata e restituire qualcos'altro, ad esempio un limite di caratteri su uno dei tuoi modelli.

2. Sarà necessario chiamare questo metodo all'interno del metodo delegato shouldChangeCharactersInRange del campo di testo. Altrimenti non sarai in grado di bloccare l'immissione di testo restituendo false, ecc.

3. Probabilmente vorrai consentire il passaggio dei caratteri backspace. Ecco perché ho aggiunto la funzione extra per rilevare i backspace. Il tuo metodo shouldChangeCharacters può verificarlo e restituire "true" all'inizio, in modo da consentire sempre i backspace.

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
    }

}

Se qualcuno di voi è interessato, ho un repository Github in cui ho preso parte di questo comportamento con limite di caratteri e l'ho inserito in un framework iOS. C'è un protocollo che puoi implementare per ottenere una visualizzazione del limite di caratteri simile a Twitter che ti mostra quanto sei andato oltre il limite di caratteri.

CharacterLimited Framework su Github


1

Poiché i delegati sono una relazione 1 a 1 e potrei volerlo utilizzare altrove per altri motivi, mi piace limitare la lunghezza del campo di testo aggiungendo questo codice all'interno della loro configurazione:

    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)

        }

0

Sto usando questo;

Limite di 3 caratteri

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
    }

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
    }

-3

È necessario verificare se la stringa esistente più l'input è maggiore di 10.

   func textField(textField: UITextField!,shouldChangeCharactersInRange range: NSRange,    replacementString string: String!) -> Bool {
      NSUInteger newLength = textField.text.length + string.length - range.length;
      return !(newLength > 10)
   }

5
Il tuo codice è sbagliato. 1. Devi dichiarare la tua costante o variabile con let o var in Swift (non NSUInteger). 2. textField.text e string sono di tipo String. La lunghezza non è una proprietà / metodo di String in Swift.
Imanou Petit
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.