Установите максимальную длину символа 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 ответа
Ваш контроллер представления должен соответствовать
UITextFieldDelegate
как показано ниже:class MyViewController: UIViewController, UITextFieldDelegate { }
Установите делегата вашего текстового поля:
myTextField.delegate = self
- Реализуйте метод в вашем контроллере вида:
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
}
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
}
}
Просто сверьтесь с количеством символов в строке
- Добавить делегата для просмотра контроллера и делегата asign
class YorsClassName: UITextFieldDelegate {
}
- проверьте количество символов, разрешенных для текстового поля
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
}
Установите делегата вашего текстового поля:
textField.delegate = self
Реализуйте метод в вашем контроллере представления:
// 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) } }
У меня есть кое-что, чтобы добавить к ответу Аладина:
Ваш контроллер представления должен соответствовать
UITextFieldDelegate
class MyViewController: UIViewController, UITextViewDelegate { }
Установка делегата вашего текстового поля. Чтобы установить делегата, вы можете управлять перетаскиванием из текстового поля на контроллер представления в раскадровке. Я думаю, что это предпочтительнее, чем устанавливать его в коде
Реализуйте метод в вашем контроллере вида:
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))
}