Longitud máxima UITextField


120

Cuando he intentado ¿Cómo configurar el número máximo de caracteres que se pueden ingresar en un UITextField usando swift? , Vi que si uso los 10 caracteres, no puedo borrar el carácter también.

Lo único que puedo hacer es cancelar la operación (eliminar todos los caracteres juntos).

¿Alguien sabe cómo no bloquear el teclado (para que no pueda agregar otras letras / símbolos / números, pero puedo usar la tecla de retroceso)?

Respuestas:


294

Con Swift 5 e iOS 12, intente la siguiente implementación del textField(_:shouldChangeCharactersIn:replacementString:)método que forma parte del UITextFieldDelegateprotocolo:

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 más importante de este código es la conversión de range( NSRange) a rangeOfTextToReplace( Range<String.Index>). Vea este video tutorial para comprender por qué esta conversión es importante.
  • Para que esto funcione correctamente el código, también se debe establecer el textField's smartInsertDeleteTypevalor a UITextSmartInsertDeleteType.no. Esto evitará la posible inserción de un espacio adicional (no deseado) al realizar una operación de pegado.

El código de ejemplo completo a continuación muestra cómo implementar textField(_:shouldChangeCharactersIn:replacementString:)en 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
    }

}

¿Acabas de poner este código en tu clase de controlador de vista? ¿O tengo que hacer conexiones?
Isaac Wasserman

Si alguien necesita poner alguna condición ... puede hacerlo así ... 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; } devuelve verdadero;
Narasimha Nallamsetty

55
Para Swift 4, text.characters.countes un uso obsoletotext.count
Mohamed Salah

47

Lo hago así:

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

El código me funciona. Pero yo trabajo con storyboard. En Storyboard agrego una acción para el campo de texto en el controlador de vista al editar la modificación .


1
countElements ha cambiado para contar en Swift 2, ¡pero cambiar eso funciona para mí!
John

1
Gracias, puede usar ahora textField.text? .Characters.count ya que countElements ha cambiado.
Anibal R.

1
Tks, funcionó muy bien con este cambio: countElements (textField.text!) En Swift 2 es: textField.text? .Characters.count
kha

32

Actualización para 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

Agregar más detalles de la respuesta de @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!) da un error. Debe usar textField.text! .Characters.count
Regis St-Gelais

1
Gracias @ RegisSt-Gelais, ya es una respuesta antigua, la actualicé ahora
Sruit A.Suk

11

En Swift 4

Límite de 10 caracteres para el campo de texto y permite eliminar (retroceso)

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

un pequeño cambio para 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

puede extender UITextField y agregar un @IBInspectableobjeto para manejarlo:

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

y luego definirlo en el inspector de atributos

ingrese la descripción de la imagen aquí

Ver la respuesta original de Swift 4


2
Bonito, código limpio. Pero por alguna razón, esto causa un comportamiento de edición extraño cuando usas emojis. El cursor salta al final de la línea cada vez que intenta editar.
Phontaine Judd

5

Si desea sobrescribir la última letra:

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

Publiqué una solución usando IBInspectable, para que pueda cambiar el valor de longitud máxima tanto en el generador de interfaces como mediante programación. Compruébalo aquí


3

Puede usar en swift 5 o swift 4, como la imagen que se ve abajo ingrese la descripción de la imagen aquí

  1. Agregar textField en View Controller
  2. Conectarse al texto a ViewController
  3. agregar el código a la vista 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;
       }
    }

Puede descargar el formulario de fuente completa 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
Me gusta la extensión Toast UIView :)
Regis St-Gelais

1

He estado usando este protocolo / extensión en una de mis aplicaciones, y es un poco más legible. Me gusta cómo reconoce los espacios de retroceso y te dice explícitamente cuándo un personaje es un espacio de retroceso.

Algunas cosas a considerar:

1. Lo que implemente esta extensión de protocolo debe especificar un límite de caracteres. Por lo general, ese será su ViewController, pero podría implementar el límite de caracteres como una propiedad calculada y devolver algo más, por ejemplo, un límite de caracteres en uno de sus modelos.

2. Deberá llamar a este método dentro del método de delegado shouldChangeCharactersInRange de su campo de texto. De lo contrario, no podrá bloquear la entrada de texto devolviendo falso, etc.

3. Probablemente desee permitir el paso de los caracteres de retroceso. Es por eso que agregué la función adicional para detectar espacios de retroceso. Su método shouldChangeCharacters puede verificar esto y devolver "verdadero" desde el principio para que siempre permita espacios atrás.

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 alguno de ustedes está interesado, tengo un repositorio de Github donde tomé parte de este comportamiento de límite de caracteres y lo puse en un marco de iOS. Hay un protocolo que puede implementar para obtener una pantalla de límite de caracteres similar a Twitter que le muestra qué tan lejos ha superado el límite de caracteres.

Marco de CharacterLimited en Github


1

Dado que los delegados tienen una relación de 1 a 1 y podría querer usarlo en otro lugar por otros motivos, me gusta restringir la longitud del campo de texto agregando este código dentro de su configuración:

    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

Estoy usando esto;

Límite 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
    }

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

Debe verificar si la cadena existente más la entrada es mayor que 10.

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

55
Tu código está mal 1. Debe declarar su constante o variable con let o var en Swift (no NSUInteger). 2. textField.text y string son de tipo String. La longitud no es una propiedad / método de String en Swift.
Imanou Petit
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.