Eu sei que existem outros tópicos sobre isso, mas não consigo descobrir como implementá-lo.
Estou tentando limitar um UITextField a apenas 5 caracteres
De preferência alfanumérico e - e. e _
Eu vi este código
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 4
let currentString: NSString = textField.text
let newString: NSString =
currentString.stringByReplacingCharactersInRange(range, withString: string)
return newString.length <= maxLength
}
e
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let length = count(textField.text.utf16) + count(string.utf16) - range.length
return length <= 10
}
Só não sei como realmente implementá-lo ou qual "campo de texto" devo trocar por meu personalizado chamado UITextField
String
no Swift atualmente, você pode finalmente apenas .prefix (n)Respostas:
Seu controlador de visualização deve estar em conformidade com
UITextFieldDelegate
, como abaixo:class MyViewController: UIViewController, UITextFieldDelegate { }
Defina o delegado do seu campo de texto:
myTextField.delegate = self
Implemente o método em seu controlador de visualização:
textField(_:shouldChangeCharactersInRange:replacementString:)
Todos juntos:
class MyViewController: UIViewController,UITextFieldDelegate //set delegate to class @IBOutlet var mytextField: UITextField // textfield variable override func viewDidLoad() { super.viewDidLoad() mytextField.delegate = self //set delegate } func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { let maxLength = 4 let currentString: NSString = textField.text let newString: NSString = currentString.stringByReplacingCharactersInRange(range, withString: string) return newString.length <= maxLength }
Para Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let maxLength = 1 let currentString: NSString = (textField.text ?? "") as NSString let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString return newString.length <= maxLength }
Permitindo que apenas um determinado conjunto de caracteres seja inserido em um determinado campo de texto
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { var result = true if mytextField == numberField { if count(string) > 0 { let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789.-").invertedSet let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil result = replacementStringIsLegal } } return result }
Como programar um campo de texto iOS que aceita apenas entrada numérica com um comprimento máximo
fonte
textField
no métodofunc textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
shouldChangeCharactersInRange
é chamado, isto é para todos os textfields, você recebe o callback no mesmo lugarshouldChangeCharactersInRange
e dentro deste método você pode saber qual textfield está sendo editado graças ao parâmetro passadotextField
você pode por exemplo dar um tag para cada campo de texto e teste dentro doshouldChangeCharactersInRange
e para cada campo de texto realizar a validação do conteúdoSwift moderno
Observe que grande parte do código de exemplo online referente a esse problema está extremamente desatualizado .
Cole o seguinte em qualquer arquivo Swift em seu projeto. (Você pode nomear o arquivo com qualquer coisa, por exemplo, "Handy.swift".)
Isso finalmente corrige um dos problemas mais estúpidos do iOS:
Seus campos de texto agora têm um
.maxLength
.É totalmente normal definir esse valor no storyboard durante o desenvolvimento ou defini-lo no código enquanto o aplicativo está em execução.
// simply have this in any Swift file, say, Handy.swift 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) } } func fix(textField: UITextField) { let t = textField.text textField.text = t?.prefix(maxLength) } }
É simples assim.
Nota de rodapé - hoje em dia, para truncar com segurança um
String
com rapidez, você simplesmente.prefix(n)
Uma versão única ainda mais simples ...
O procedimento acima corrige todos os campos de texto em seu projeto.
Se você deseja apenas que um determinado campo de texto seja simplesmente limitado a dizer "4", e pronto ...
class PinCodeEntry: UITextField { override func didMoveToSuperview() { super.didMoveToSuperview() addTarget(self, action: #selector(fixMe), for: .editingChanged) } @objc private func fixMe() { text = text?.prefix(4) } }
Ufa! Isso é tudo que há para fazer.
(A propósito, aqui está uma dica semelhante muito útil relacionada ao UIText View , https://stackoverflow.com/a/42333832/294884 )
Para o programador OCD (como eu) ...
Como @LeoDabus lembra,
.prefix
retorna uma substring. Se você é extremamente atencioso, estelet t = textField.text textField.text = t?.prefix(maxLength)
seria
if let t: String = textField.text { textField.text = String(t.prefix(maxLength)) }
Apreciar!
fonte
Swift 4, basta usar:
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { return range.location < 10 }
fonte
string.count < MAX_LENGTH
Da mesma forma que Steven Schmatz fez, mas usando o Swift 3.0:
//max Length func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let maxLength = 4 let currentString: NSString = textField.text! as NSString let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString return newString.length <= maxLength }
fonte
Para Swift 5:
basta escrever uma linha para definir o comprimento máximo de caracteres:
self.textField.maxLength = 10
Para mais detalhes clique aqui
Crédito: http://www.swiftdevcenter.com/max-character-limit-of-uitextfield-and-allowed-characters-swift/
fonte
Acho que a extensão é mais útil para isso. Veja a resposta completa aqui
private var maxLengths = [UITextField: Int]() // 2 extension UITextField { // 3 @IBInspectable var maxLength: Int { get { // 4 guard let length = maxLengths[self] else { return Int.max } return length } set { maxLengths[self] = newValue // 5 addTarget( self, action: #selector(limitLength), forControlEvents: UIControlEvents.EditingChanged ) } } func limitLength(textField: UITextField) { // 6 guard let prospectiveText = textField.text where prospectiveText.characters.count > maxLength else { return } let selection = selectedTextRange // 7 text = prospectiveText.substringWithRange( Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength)) ) selectedTextRange = selection } }
fonte
Outras soluções postadas acima produzem um ciclo de retenção devido ao mapa de campo de texto. Além disso, a
maxLength
propriedade deve ser anulável se não for definida em vez deInt.max
construções artificiais ; e o destino será definido várias vezes se maxLength for alterado.Aqui, uma solução atualizada para Swift4 com um mapa fraco para evitar vazamentos de memória e outras correções
private var maxLengths = NSMapTable<UITextField, NSNumber>(keyOptions: NSPointerFunctions.Options.weakMemory, valueOptions: NSPointerFunctions.Options.strongMemory) extension UITextField { var maxLength: Int? { get { return maxLengths.object(forKey: self)?.intValue } set { removeTarget(self, action: #selector(limitLength), for: .editingChanged) if let newValue = newValue { maxLengths.setObject(NSNumber(value: newValue), forKey: self) addTarget(self, action: #selector(limitLength), for: .editingChanged) } else { maxLengths.removeObject(forKey: self) } } } @IBInspectable var maxLengthInspectable: Int { get { return maxLength ?? Int.max } set { maxLength = newValue } } @objc private func limitLength(_ textField: UITextField) { guard let maxLength = maxLength, let prospectiveText = textField.text, prospectiveText.count > maxLength else { return } let selection = selectedTextRange text = String(prospectiveText[..<prospectiveText.index(from: maxLength)]) selectedTextRange = selection } }
fonte
Solução simples sem usar delegado:
TEXT_FIELD.addTarget(self, action: #selector(editingChanged(sender:)), for: .editingChanged) @objc private func editingChanged(sender: UITextField) { if let text = sender.text, text.count >= MAX_LENGHT { sender.text = String(text.dropLast(text.count - MAX_LENGHT)) return } }
fonte
Minha versão do Swift 4 de
shouldChangeCharactersIn
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { guard let preText = textField.text as NSString?, preText.replacingCharacters(in: range, with: string).count <= MAX_TEXT_LENGTH else { return false } return true }
fonte
Tenho algo a acrescentar à resposta de Aladin:
Seu controlador de visualização deve estar em conformidade com
UITextFieldDelegate
class MyViewController: UIViewController, UITextViewDelegate { }
Defina o delegado do seu campo de texto: para definir o delegado, você pode controlar o arrasto do campo de texto para o controlador de visualização no storyboard. Eu acho que isso é preferível a defini-lo em código
Implemente o método em seu controlador de visualização:
textField(_:shouldChangeCharactersInRange:replacementString:)
fonte
Dou uma resposta complementar baseada em @Frouo. Acho que a resposta dele é a mais linda. Porque é um controle comum que podemos reutilizar. E não há problema de vazamento aqui.
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) } } //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 } 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 } }
fonte
atualização para esta resposta Fattie
obrigado
extension UITextField { /// Runtime key private struct AssociatedKeys { /// max lenght key static var maxlength: UInt8 = 0 /// temp string key static var tempString: UInt8 = 0 } /// Limit the maximum input length of the textfiled @IBInspectable var maxLength: Int { get { return objc_getAssociatedObject(self, &AssociatedKeys.maxlength) as? Int ?? 0 } set { objc_setAssociatedObject(self, &AssociatedKeys.maxlength, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) addTarget(self, action: #selector(handleEditingChanged(textField:)), for: .editingChanged) } } /// temp string private var tempString: String? { get { return objc_getAssociatedObject(self, &AssociatedKeys.tempString) as? String } set { objc_setAssociatedObject(self, &AssociatedKeys.tempString, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } /// When the text changes, process the amount of text in the input box so that its length is within the controllable range. @objc private func handleEditingChanged(textField: UITextField) { /// Special Processing for Chinese Input Method guard markedTextRange == nil else { return } if textField.text?.count == maxLength { /// SET lastQualifiedString where text length == max lenght tempString = textField.text } else if textField.text?.count ?? 0 < maxLength { /// clear lastQualifiedString when text lengeht > maxlength tempString = nil } /// keep current text range in arcgives let archivesEditRange: UITextRange? if textField.text?.count ?? 0 > maxLength { /// if text length > maxlength,remove last range,to move to -1 postion. let position = textField.position(from: safeTextPosition(selectedTextRange?.start), offset: -1) ?? textField.endOfDocument archivesEditRange = textField.textRange(from: safeTextPosition(position), to: safeTextPosition(position)) } else { /// just set current select text range archivesEditRange = selectedTextRange } /// main handle string max length textField.text = tempString ?? String((textField.text ?? "").prefix(maxLength)) /// last config edit text range textField.selectedTextRange = archivesEditRange } /// get safe textPosition private func safeTextPosition(_ optionlTextPosition: UITextPosition?) -> UITextPosition { /* beginningOfDocument -> The end of the the text document. */ return optionlTextPosition ?? endOfDocument } }
fonte
Trabalhando em Swift4
// PASSO 1 definir UITextFieldDelegate
class SignUPViewController: UIViewController , UITextFieldDelegate { @IBOutlet weak var userMobileNoTextFiled: UITextField! override func viewDidLoad() { super.viewDidLoad()
// PASSO 2 definir delegado
userMobileNoTextFiled.delegate = self // definir delegado}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // guard let text = userMobileNoTextFiled.text else { return true } // let newLength = text.count + string.count - range.length // return newLength <= 10 // }
// PASSO 3 chamar função
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let maxLength = 10 // set your need let currentString: NSString = textField.text! as NSString let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString return newString.length <= maxLength } }
fonte
Esta resposta é para o Swift 4 e é bastante simples com a capacidade de retroceder.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { return textField.text!.count < 10 || string == "" }
fonte
Basta verificar o número de caracteres na string
class YorsClassName : UITextFieldDelegate { }
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if textField.text?.count == 1 { return false } return true }
Nota: Aqui, verifiquei apenas os caracteres permitidos em textField
fonte
Caractere de limite de TextField após bloquear o texto no Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,replacementString string: String) -> Bool { if textField == self.txtDescription { let maxLength = 200 let currentString: NSString = textField.text! as NSString let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString return newString.length <= maxLength } return true }
fonte
Por precaução, não se esqueça de proteger o tamanho do alcance antes de aplicá-lo à corda. Caso contrário, você travará se o usuário fizer isso:
Digite o texto de comprimento máximo Insira algo (nada será inserido devido à limitação de comprimento, mas o iOS não sabe sobre isso) Desfaça a inserção (você obtém travamento, pois o intervalo será maior do que o tamanho real da string)
Além disso, os usuários do iOS 13 podem acidentalmente acionar isso por meio de gestos
Eu sugiro que você adicione ao seu projeto este
extension String { func replace(with text: String, in range: NSRange) -> String? { guard range.location + range.length <= self.count else { return nil } return (self as NSString).replacingCharacters(in: range, with: text) } }
E use-o assim:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { guard let newText = textView.text.replace(with: text, in: range) else { return false } return newText.count < maxNumberOfCharacters }
Caso contrário, você travará constantemente em seu aplicativo
fonte
Aqui está uma alternativa do Swift 3.2+ que evita a manipulação desnecessária de strings. Nesse caso, o comprimento máximo é 10:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let text = textField.text ?? "" return text.count - range.length + string.count <= 10 }
fonte
Eu uso esta etapa, primeiro Set delegate texfield em viewdidload.
override func viewDidLoad() { super.viewDidLoad() textfield.delegate = self }
e, em seguida, deveChangeCharactersIn depois de incluir UITextFieldDelegate.
extension viewController: UITextFieldDelegate { func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let newLength = (textField.text?.utf16.count)! + string.utf16.count - range.length if newLength <= 8 { return true } else { return false } } }
fonte
Se você tiver vários textField com várias verificações de comprimento em uma página, encontrei uma solução fácil e curta.
class MultipleTextField: UIViewController { let MAX_LENGTH_TEXTFIELD_A = 10 let MAX_LENGTH_TEXTFIELD_B = 11 lazy var textFieldA: UITextField = { let textField = UITextField() textField.tag = MAX_LENGTH_TEXTFIELD_A textField.delegate = self return textField }() lazy var textFieldB: UITextField = { let textField = UITextField() textField.tag = MAX_LENGTH_TEXTFIELD_B textField.delegate = self return textField }() } extension MultipleTextField: UITextFieldDelegate { func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { return (range.location < textField.tag) && (string.count < textField.tag) } }
fonte