在Swift中设置UITextField的最大字符长度

124

我知道这个话题已经有其他相关的讨论了,但是我似乎找不到如何实现它。

我正在尝试将一个UITextField限制为只能输入5个字符。

最好是字母数字、-._

我看到了这段代码:

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
}

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
}

我该如何实际应用它?我应该用哪个“textfield”来替换我的自定义UITextField?


Swift 4 实现 https://stackoverflow.com/a/46513151/2303865 - Leo Dabus
快速提醒 - 在Swift中缩短一个String的长度,现在你终于可以用.prefix(n)来实现了。 - Fattie
23个回答

3

更新Fattie的回答

extension UITextField {

    // Runtime key
    private struct AssociatedKeys {
        // Maximum length key
        static var maxlength: UInt8 = 0
        // Temporary 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)
        }
    }

    // Temporary 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 the Chinese input method
        guard markedTextRange == nil else { return }

        if textField.text?.count == maxLength {

            // Set lastQualifiedString where text length == maximum length
            tempString = textField.text
        } else if textField.text?.count ?? 0 < maxLength {

            // Clear lastQualifiedString when text length > maxlength
            tempString = nil
        }

        // Keep the current text range in arcgives
        let archivesEditRange: UITextRange?

        if textField.text?.count ?? 0 > maxLength {

            // If text length > maximum length, remove last range and 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 maximum length
        textField.text = tempString ?? String((textField.text ?? "").prefix(maxLength))

        // Last configuration 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
    }
}

3

只需检查字符串中的字符数即可。

  1. Add a delegate to view controller and assign the delegate

    class YorsClassName : UITextFieldDelegate {
    
    }
    
  2. Check the number of characters allowed for the text field

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if textField.text?.count == 1 {
            return false
        }
        return true
    }
    
注意:这里我只检查了textField中允许的字符。

最后一句话是什么意思?你能详细解释一下吗?什么没有被检查?仅仅检查了什么?例如,你的意思是“这里我只检查了textField中允许的字符”吗?请通过编辑(更改)您的答案来回复,而不是在评论中回复(不要包含“Edit:”,“Update:”或类似的内容 - 答案应该看起来像今天写的)。 - Peter Mortensen

2

我需要补充一下Alaeddine的答案

  1. Your view controller should conform to UITextFieldDelegate

     class MyViewController: UIViewController, UITextViewDelegate {
    
     }
    
  2. Set the delegate of your textfield:

    To set the delegate, you can control drag from the textfield to your view controller in the storyboard. I think this is preferable to setting it in code

  3. Implement the method in your view controller:

     textField(_:shouldChangeCharactersInRange:replacementString:)
    

2
  1. Set the delegate of your textfield:

     textField.delegate = self
    
  2. Implement the method in your view controller:

     // MARK: Text field delegate
    
     extension ViewController: UITextFieldDelegate {
         func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
             return range.location < maxLength (maxLength can be any maximum length you can define)
         }
     }
    

2

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


}

1
这个答案适用于Swift 4,非常简单,可以让退格键通过。
func textField(_ textField: UITextField,
               shouldChangeCharactersIn range: NSRange,
               replacementString string: String) -> Bool {
    return textField.text!.count < 10 || string == ""
}

这个不处理复制和粘贴。 - cornr

1

这在Swift 4中有效

步骤1:设置UITextFieldDelegate

class SignUPViewController: UIViewController , UITextFieldDelegate {

   @IBOutlet weak var userMobileNoTextFiled: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

步骤二:设置代理

        userMobileNoTextFiled.delegate = self                  // Set delegate
   }

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

步骤三:调用函数

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

1

我使用以下步骤。首先在viewdidload中设置委托文本字段。

override func viewDidLoad() {
    super.viewDidLoad()

    textfield.delegate = self
}

在包含UITextFieldDelegate之后,您应该使用shouldChangeCharactersIn函数。
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
        }
    }
}

1
这里提供了一种Swift 3.2+的替代方案,避免了不必要的字符串操作。在本例中,最大长度为10:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let text = textField.text ?? ""

    return text.count - range.length + string.count <= 10
}

1

为了避免出现问题,请在将范围大小应用于字符串之前确保对其进行保护。否则,如果用户执行以下操作,您将会遇到崩溃:

  • 输入最大长度文本
  • 插入某些内容(由于长度限制,不会插入任何内容,但iOS并不知道这一点)
  • 撤消插入操作(您将遇到崩溃,因为范围将超过实际字符串大小)

此外,使用iOS 13,用户可能会意外触发此问题。

我建议您将此添加到您的项目中:

extension String {
    func replace(with text: String, in range: NSRange) -> String? {
        // NOTE: NSString conversion is necessary to operate in the same symbol steps
        // Otherwise, you may not be able to delete an emoji, for example
        let current = NSString(string: self)
        guard range.location + range.length <= current.length else { return nil }
        return current.replacingCharacters(in: range, with: text)
    }
}

并像这样使用:

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
    // NOTE: You may wanna trim the new text instead,
    // so the user will able to shove his long text at least partially
}

否则,您的应用程序将经常崩溃。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接