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

Giorgio Nocera
fuente

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
    }

}
Imanou Petit
fuente
¿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 .

Martín
fuente
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
}
Shan Ye
fuente
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()
    }
}
Sruit A.Suk
fuente
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
    }
Sai kumar Reddy
fuente
8
func checkMaxLength(textField: UITextField!, maxLength: Int) {
        if (textField.text!.characters.count > maxLength) {
            textField.deleteBackward()
        }
}

un pequeño cambio para iOS 9

Jeremy Andrews
fuente
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
    }
Albahaca mariano
fuente
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

Mohsen
fuente
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
}
maxwell
fuente
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í

frouo
fuente
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

Enamul Haque
fuente
1

Tenga cuidado con el error de deshacer para UITextField mencionado en esta publicación: establezca la longitud máxima de caracteres de un UITextField

así es como lo arreglas rápidamente

if(range.length + range.location > count(textField.text)) {
        return false;
}
Horacio
fuente
Si desea admitir emoji y tal uso: 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
fuente
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

Theo Bendixson
fuente
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)

        }
MQLN
fuente
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
    }
alicanozkara
fuente
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
fuente
-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)
   }
bhzag
fuente
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