Установите максимальную длину символа UITextField в Swift

Я знаю, что есть другие темы по этому вопросу, но я не могу понять, как это реализовать.

Я пытаюсь ограничить 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 
}

Я просто не знаю, как на самом деле реализовать это или какое "текстовое поле" я должен поменять для своего обычая с именем UITextField

23 ответа

Решение
  1. Ваш контроллер представления должен соответствовать UITextFieldDelegateкак показано ниже:

    class MyViewController: UIViewController, UITextFieldDelegate {
    
    }
    
  2. Установите делегата вашего текстового поля: myTextField.delegate = self

  3. Реализуйте метод в вашем контроллере вида: textField(_:shouldChangeCharactersInRange:replacementString:)

Все вместе:

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
}

Для 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
}

Допускается ввод только указанного набора символов в данное текстовое поле

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
}

Как запрограммировать текстовое поле iOS, которое принимает только числовой ввод с максимальной длиной

2017

Декабрь 2017. Swift 4.

Весь пример кода для этого очень устарел.

Просто вставьте следующее в любой файл Swift в вашем проекте. (Вы можете назвать файл как угодно, например, "Handy.swift")

Это наконец исправляет одну из самых глупых проблем в iOS:

Ваши текстовые поля теперь имеют .maxLength,

Вполне допустимо установить это значение в раскадровке или в коде.

// simply have this in a file called, say, Handy.swift or TextUtility.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?.safelyLimitedTo(length: maxLength)
    }
}

extension String
    {
    func safelyLimitedTo(length n: Int)->String {
        if (self.count <= n) {
            return self
        }
        return String( Array(self).prefix(upTo: n) )
    }
}

Это так просто.


(Примечание: "safeLimitedTo#length" - это просто вызов, который обрезает длину строки. Почти все программисты Swift имеют свою собственную функцию для этого, или вы можете просто использовать мою там.)

Кстати, вот похожий, невероятно полезный совет, касающийся UITextView, /questions/29615232/kak-poteryat-polya-otstupyi-v-uitextview/29615246#29615246


Еще версия KISS...

Потому что эта проблема невероятно раздражает:

Часто вам просто нужно одно специальное текстовое поле, которое просто ограничено ("и это все!") Определенной длиной.

Например, пин-код состоит из четырех символов, и все.

Это так просто:

class PinCodeEntry: UITextField {

    override func didMoveToSuperview() {

        super.didMoveToSuperview()
        addTarget(self, action: #selector(fixMe), for: .editingChanged)
    }

    @objc private func fixMe() { text = text?.safelyLimitedTo(length 4) }
}

Уф! Это все, что нужно сделать.

Swift 4, просто используйте:

public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    return range.location < 10
}

Стивен Шмац сделал то же самое, но с помощью 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
}

Для Swift 5:
просто напишите одну строку, чтобы установить максимальную длину символа:

 self.textField.maxLength = 10

Для более подробной информации нажмите здесь

Кредит: http://www.swiftdevcenter.com/max-character-limit-of-uitextfield-and-allowed-characters-swift/

Простое решение без использования делегата:

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

Я думаю, что расширение более удобно для этого. Смотрите полный ответ здесь

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
  }

}

Моя Свифт 4 версия 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
    }

Другие решения, опубликованные выше, создают цикл сохранения из-за карты текстового поля. Кроме maxLength свойство должно быть обнуляемым, если оно не установлено вместо искусственного Int.max конструкции; и цель будет установлена ​​несколько раз, если maxLength изменяется.

Здесь обновленное решение для Swift4 со слабой картой для предотвращения утечек памяти и других исправлений

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

Обновление для этого толстяка ответ

import UIKit

extension UITextField {

    /// Runtime 键
    private struct AssociatedKeys {

        static var maxlength: UInt8 = 0
        static var lastString: UInt8 = 0
    }

    /// 最大输入长度
    @IBInspectable var maxLength: Int {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.maxlength) as? Int ?? 0
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKeys.maxlength, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            addTarget(self, action: #selector(fix), for: .editingChanged)
        }
    }

    /// 最后一个符合条件的规则
    private var lastQualifiedString: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.lastString) as? String
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKeys.lastString, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    @objc func fix(textField: UITextField) {

        guard markedTextRange == nil else { return }

        /// 如果 个数 为最大个数
        /// 在字典中,保存 最大数据
        if textField.text?.count == maxLength {

            /// 在 字典中保存 该数值
            lastQualifiedString = textField.text

            // 在 小于个数时 清除 数据
        } else if textField.text?.count ?? 0 < maxLength {
            lastQualifiedString = nil
        }

        let editRange: UITextRange?

        /// 如果 输入框内的个数大于 最大值
        if textField.text?.count ?? 0 > maxLength {

            /// 将选中的 range 向前移动一个位置
            let position = textField.position(from: safeTextPosition(selectedTextRange?.start), offset: -1) ?? textField.beginningOfDocument

            editRange = textField.textRange(from: safeTextPosition(position), to: safeTextPosition(position))
        } else {

            editRange = selectedTextRange
        }

        /// 配置 值
        textField.text = textField.text?.safelyLimitedTo(length: maxLength, safeText: lastQualifiedString)

        textField.selectedTextRange = editRange
    }

    /// 安全获取  UITextPosition
    private func safeTextPosition(_ optionlTextPosition: UITextPosition?) -> UITextPosition {

        /* beginningOfDocument -> The end and beginning of the the text document. */
        return optionlTextPosition ?? self.beginningOfDocument
    }
}

extension String {

    /// 比较后 决定 返回 text 还是 safetext
    ///
    /// - Parameters:
    ///   - n: 长度
    ///   - safeText: 安全字符串
    /// - Returns: 返回的值
    fileprivate func safelyLimitedTo(length n: Int, safeText: String?) -> String? {
        if (self.count <= n) {
            return self
        }
        return safeText ?? String( Array(self).prefix(upTo: n) )
    }
}

Этот ответ предназначен для Swift 4 и довольно прост с возможностью пропустить пробел.

func textField(_ textField: UITextField, 
               shouldChangeCharactersIn range: NSRange, 
               replacementString string: String) -> Bool {
    return textField.text!.count < 10 || string == ""
}

Я даю дополнительный ответ на основе @Frouo. Я думаю, что его ответ - самый красивый способ. Потому что это общий контроль, который мы можем использовать повторно. И здесь нет проблем с утечкой.

    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
        }



    }

Просто сверьтесь с количеством символов в строке

  1. Добавить делегата для просмотра контроллера и делегата asign

class YorsClassName: UITextFieldDelegate {

}

  1. проверьте количество символов, разрешенных для текстового поля

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replaceString string: String) -> Bool { if textField.text?.count == 1 { return false } вернуть true }

Примечание: здесь я проверил только разрешенный символ в textField

Символ ограничения текстового поля после блока текста в 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. Установите делегата вашего текстового поля:

             textField.delegate = self
    
  2. Реализуйте метод в вашем контроллере представления:

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

У меня есть кое-что, чтобы добавить к ответу Аладина:

  1. Ваш контроллер представления должен соответствовать UITextFieldDelegate

    class MyViewController: UIViewController, UITextViewDelegate {
    
    }
    
  2. Установка делегата вашего текстового поля. Чтобы установить делегата, вы можете управлять перетаскиванием из текстового поля на контроллер представления в раскадровке. Я думаю, что это предпочтительнее, чем устанавливать его в коде

  3. Реализуйте метод в вашем контроллере вида: textField(_:shouldChangeCharactersInRange:replacementString:)

Я использую этот шаг, сначала установите делегат texfield в viewdidload.

    override func viewDidLoad() {
        super.viewDidLoad()

        textfield.delegate = self

    }

а затем следует изменить CharactersIn после включения 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
                }
            }
    }

Работая в Swift4

// ШАГ 1 set UITextFieldDelegate

    class SignUPViewController: UIViewController , UITextFieldDelegate {

       @IBOutlet weak var userMobileNoTextFiled: UITextField!

        override func viewDidLoad() {
            super.viewDidLoad()

// ШАГ 2 установить делегата
userMobileNoTextFiled.delegate = self // установить делегата}

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

// ШАГ 3 вызов функции

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

На всякий случай не забудьте защитить размер диапазона перед его применением к строке. В противном случае произойдет сбой, если пользователь сделает следующее:

Введите текст максимальной длины Вставьте что-нибудь (ничего не будет вставлено из-за ограничения длины, но iOS не знает об этом) Отменить вставку (происходит сбой, диапазон причин будет больше, чем фактический размер строки)

Также при использовании iOS 13 пользователи могут случайно вызвать это жестами.

Предлагаю вам добавить в свой проект это

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

И используйте это так:

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
}

В противном случае ваше приложение будет постоянно падать.

Вот альтернатива 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
}

Если у вас есть несколько текстовых полей с проверками разной длины на одной странице, я нашел простое и короткое решение.

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

Просматривая эти ответы, я не смог полностью разгадать ответ, который искал (но это мог быть я). Я искал установку максимального количества символов в двух текстовых полях (но можно сделать больше, расширив else) в одном представлении. Решение, которое я нашел, которое я также нашел наиболее чистым, — это расширение. Вот код, просто настройте место здесь с помощью вашего VC и текстового поля.

      extension PlaceYourViewControllerHere: UITextFieldDelegate {

private var maxCharacters: Int = 24

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
    }
    if textField == placeFirstTextfieldHere { maxCharacters = 64 } else { maxCharacters = 255 }
    let substringToReplace = textFieldText[rangeOfTextToReplace]
    let count = textFieldText.count - substringToReplace.count + string.count
    return count <= maxCharacters
    }

}

Изменить: не забудьте установить делегата в текстовом поле.

              textField.delegate = self
      lazy var textField: UITextField = {
  let textField = UITextField()
  textField.addTarget(self, #selector(handleOnEditing), for .editingChanged)
  return textField
}()

//Установить делегата в ViewDidLoadtextField.delegate = self

      @objc func handleOnEditing() {
   let text = textField.text ?? ""
   let limit = 10
   textField.text = String(text.prefix(limit))
}
Другие вопросы по тегам