Максимальная длина UITextField

120

Когда я пробовал Как установить максимальное количество символов, которое можно ввести в UITextField с помощью swift? , Я увидел, что если я использую все 10 символов, я тоже не могу стереть символ.

Единственное, что я могу сделать, это отменить операцию (удалить все символы вместе).

Кто-нибудь знает, как не блокировать клавиатуру (чтобы я не мог добавлять другие буквы / символы / цифры, но могу использовать backspace)?

Джорджио Ночера
источник

Ответы:

295

В Swift 5 и iOS 12 попробуйте следующую реализацию textField(_:shouldChangeCharactersIn:replacementString:)метода, являющегося частью UITextFieldDelegateпротокола:

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
}
  • Самая важная часть этого кода - преобразование из range( NSRange) в rangeOfTextToReplace( Range<String.Index>). Посмотрите этот видеоурок, чтобы понять, почему это преобразование важно.
  • Для того, чтобы этот код работает правильно, вы должны также установить textField«S smartInsertDeleteTypeзначение UITextSmartInsertDeleteType.no. Это предотвратит возможную вставку (нежелательного) лишнего пробела при выполнении операции вставки.

Полный пример кода ниже показывает, как реализовать textField(_:shouldChangeCharactersIn:replacementString:)в 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
    }

}
Иману Пети
источник
Вы просто помещаете этот код в свой класс контроллера представления? Или мне нужно наладить связи?
Исаак Вассерман,
Если кому-то нужно поставить какое-то условие .. можно сделать вот так ... if (textField .isEqual (mobileNumberTextfield)) {охранник let text = textField.text else {return true} let newLength = text.characters.count + string.characters.count - range.length return newLength <= limitLength; } вернуть истину;
Нарасимха Налламсетти
6
Для Swift 4 text.characters.countиспользование не рекомендуетсяtext.count
Мохамед Салах
47

Я так делаю:

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

Код у меня работает. Но я работаю с раскадровкой. В Storyboard я добавляю действие для текстового поля в контроллере представления при изменении редактирования .

Мартин
источник
1
countElements был изменен на счетчик в Swift 2, но изменение этого работает для меня!
Джон
1
Спасибо, теперь вы можете использовать textField.text? .Characters.count, так как countElements был изменен.
Anibal R.
1
Спасибо, он отлично поработал с этим изменением: countElements (textField.text!) В Swift 2: textField.text? .Characters.count
kha
33

Обновление для 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

Добавить подробности из ответа @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!) выдает ошибку. Вы должны использовать textField.text! .Characters.count
Regis St-Gelais
1
Спасибо @ RegisSt-Gelais, это уже старый ответ, я обновил его сейчас
Sruit A.Suk
11

В Swift 4

Ограничение на 10 символов для текстового поля и разрешение на удаление (backspace)

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

небольшое изменение для 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

вы можете расширить UITextField и добавить @IBInspectableобъект для его обработки:

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

и после этого определите его в инспекторе атрибутов

введите описание изображения здесь

См. Оригинальный ответ Swift 4

Мохсен
источник
2
Хороший чистый код. Но по какой-то причине это вызывает странное поведение редактирования при использовании эмодзи. Курсор переходит в конец строки при каждой попытке редактирования.
Phontaine Judd
5

Если вы хотите перезаписать последнюю букву:

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

Я опубликовал решение using IBInspectable, поэтому вы можете изменить значение максимальной длины как в построителе интерфейса, так и программно. Посмотрите здесь

frouo
источник
3

Вы можете использовать Swift 5 или Swift 4, как изображение ниже введите описание изображения здесь

  1. Добавить текстовое поле в View Controller
  2. Подключиться к тексту в ViewController
  3. добавить код в представление 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;
       }
    }

Вы можете скачать полный исходный код с GitHub: https://github.com/enamul95/TextFieldMaxLen

Энамул Хак
источник
1

Остерегайтесь ошибки отмены для UITextField, упомянутой в этом сообщении: установите максимальную длину символа UITextField

вот как быстро это исправить

if(range.length + range.location > count(textField.text)) {
        return false;
}
Горацио
источник
Если вы хотите поддерживать смайлики и такое использование: 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
источник
1
Мне нравится расширение Toast UIView :)
Regis St-Gelais
1

Я использовал этот протокол / расширение в одном из своих приложений, и он стал немного более читаемым. Мне нравится, как он распознает пробелы и явно сообщает вам, когда символ является пробелом.

Что следует учитывать:

1. Независимо от того, что реализует это расширение протокола, необходимо указать ограничение на количество символов. Обычно это будет ваш ViewController, но вы можете реализовать ограничение на количество символов как вычисляемое свойство и вернуть что-то еще, например ограничение на количество символов для одной из ваших моделей.

2. Вам нужно будет вызвать этот метод внутри метода делегата shouldChangeCharactersInRange текстового поля. В противном случае вы не сможете заблокировать ввод текста, вернув false и т. Д.

3. Возможно, вы захотите пропустить символы возврата. Вот почему я добавил дополнительную функцию для обнаружения пробелов. Ваш метод shouldChangeCharacters может проверить это и на раннем этапе вернуть true, поэтому вы всегда разрешаете возврат.

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
    }

}

Если кому-то из вас интересно, у меня есть репозиторий Github, где я взял некоторые из этих ограничений на количество символов и поместил их в платформу iOS. Существует протокол, который вы можете реализовать, чтобы получить отображение предельного количества символов в стиле Twitter, которое показывает, насколько вы далеко превысили лимит символов.

CharacterLimited Framework на Github

Тео Бендиксон
источник
1

Поскольку делегаты являются отношениями один-к-одному, и я мог бы использовать его в другом месте по другим причинам, мне нравится ограничивать длину текстового поля, добавляя этот код в их настройку:

    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
источник
0

Я использую это;

Ограничить 3 символа

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
источник
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
источник
-3

Вам нужно проверить, больше ли существующая строка плюс ввод больше 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
источник
5
Ваш код неверен. 1. Вы должны объявить свою константу или переменную с помощью let или var в Swift (не NSUInteger). 2. textField.text и строка имеют тип String. Длина не является свойством / методом String в Swift.
Иману Пети