Как установить максимальное количество символов в UITextField
в iPhone SDK при загрузке UIView
?
Установите максимальную длину символа UITextField
Ответы (44)
Хотя у класса UITextField
нет свойства максимальной длины, относительно просто получить эту функциональность, установив delegate
в текстовом поле и реализовав следующий метод делегата:
Цель-C
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Prevent crashing undo bug – see note below.
if(range.length + range.location > textField.text.length)
{
return NO;
}
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return newLength <= 25;
}
Swift
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentCharacterCount = textField.text?.count ?? 0
if range.length + range.location > currentCharacterCount {
return false
}
let newLength = currentCharacterCount + string.count - range.length
return newLength <= 25
}
Перед изменением текстового поля UITextField спрашивает делегата, следует ли изменить указанный текст. Текстовое поле на данный момент не изменилось, поэтому мы берем его текущую длину и длину вставляемой строки (либо путем вставки скопированного текста, либо путем ввода одного символа с помощью клавиатуры) за вычетом длины диапазона. Если это значение слишком длинное (более 25 символов в этом примере), верните NO
, чтобы запретить изменение.
При вводе одного символа в конце текстового поля range.location
будет длиной текущего поля, а range.length
будет 0, потому что мы ничего не заменяем / не удаляем. Вставка в середину текстового поля означает просто другой range.location
, а вставка нескольких символов просто означает, что string
содержит более одного символа.
Удаление отдельных символов или вырезание нескольких символов определяется range
с ненулевой длиной и пустой строкой. Замена - это просто удаление диапазона непустой строкой.
Замечание о сбойной ошибке отмены
Как упоминается в комментариях, есть ошибка с UITextField
, которая может привести к сбою.
Если вы вставляете в поле, но вставка предотвращается вашей реализацией проверки, операция вставки все равно записывается в буфере отмены приложения. Если затем выполнить отмену (встряхнув устройство и подтвердив отмену), UITextField
попытается заменить строку, которую думает, которую он вставил в себя, пустой строкой. Это приведет к сбою, потому что он никогда фактически не вставлял строку в себя. Он попытается заменить несуществующую часть строки.
К счастью, вы можете защитить UITextField
от подобного самоубийства. Вам просто нужно убедиться, что диапазон, который он предлагает заменить, действительно существует в его текущей строке. Это то, что делает приведенная выше начальная проверка работоспособности.
swift 3.0 с копией и вставкой работает нормально.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let str = (textView.text + text)
if str.characters.count <= 10 {
return true
}
textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
return false
}
Надеюсь, это поможет вам.
return newLength <= 25;
- person jowie; 26.02.2013
UITextField
на iPad iOS 8.1. (+1 к комментарию). Может ли автор что-нибудь добавить по этому поводу, так как это самый популярный ответ? Я счастлив сделать правку, но мне регулярно отказывают! :-)
- person Benjohn; 24.11.2014
-textField:shouldChangeCharactersInRange:replacementString
метод делегата. Я думаю, что для полноты ответа об этом стоит упомянуть.
- person Jakub Vano; 14.04.2015
count(textField.text)
должен быть textField.text?.characters.count
- person funroll; 17.09.2015
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
- person Jonny; 31.03.2017
range.length
›1). К сожалению, классы NSRange
и String
не очень совместимы, поэтому вы можете столкнуться с подобными проблемами. Вам нужно преобразовать в NSString
объектов. Я выложу решение.
- person Guy Kogus; 07.04.2017
-(BOOL)textField:(UITextField*)tf shouldChangeCharactersInRange:(NSRange)r replacementString:(NSString*)s {return [tf.text stringByReplacingCharactersInRange:r withString:s].length <= 3;}
Это можно воспроизвести на японском языке - клавиатура ромадзи
- person igrek; 17.11.2017
string.count
экземпляров до string.utf16.count
исправляет эту ошибку.
- person Ryan Maloney; 30.04.2021
Swift 4
import UIKit
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)
addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
}
}
@objc func checkMaxLength(textField: UITextField) {
guard let prospectiveText = self.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
let substring = prospectiveText[..<indexEndOfText]
text = String(substring)
selectedTextRange = selection
}
}
Изменить: исправлена проблема с утечкой памяти.
Спасибо, август! (Сообщение)
Вот код, который у меня в итоге работает:
#define MAX_LENGTH 20
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField.text.length >= MAX_LENGTH && range.length == 0)
{
return NO; // return NO to not change text
}
else
{return YES;}
}
return textField.text.length < MAX_LENGTH || range.length != 0;
- person igrek; 21.11.2017
Чтобы завершить ответ августа, возможная реализация предложенной функции (см. делегат UITextField).
Я не тестировал код domness, но мой код не застревает, если пользователь достиг предела, и он совместим с новой строкой, которая заменяет меньшую или равную.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//limit the size :
int limit = 20;
return !([textField.text length]>limit && [string length] > range.length);
}
Вы не можете сделать это напрямую - UITextField
не имеет атрибута maxLength, но вы можете установить делегат UITextField's
, а затем использовать:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Часто у вас есть несколько полей ввода разной длины.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
int allowedLength;
switch(textField.tag) {
case 1:
allowedLength = MAXLENGTHNAME; // triggered for input fields with tag = 1
break;
case 2:
allowedLength = MAXLENGTHADDRESS; // triggered for input fields with tag = 2
break;
default:
allowedLength = MAXLENGTHDEFAULT; // length default when no tag (=0) value =255
break;
}
if (textField.text.length >= allowedLength && range.length == 0) {
return NO; // Change not allowed
} else {
return YES; // Change allowed
}
}
Лучше всего настроить уведомление об изменении текста. В вашем -awakeFromNib
методе контроллера представления вам понадобится:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(limitTextField:) name:@"UITextFieldTextDidChangeNotification" object:myTextField];
Затем в том же классе добавьте:
- (void)limitTextField:(NSNotification *)note {
int limit = 20;
if ([[myTextField stringValue] length] > limit) {
[myTextField setStringValue:[[myTextField stringValue] substringToIndex:limit]];
}
}
Затем подключите выход myTextField
к своему UITextField
, и он не позволит вам добавлять больше символов после достижения лимита. Не забудьте добавить это в свой метод dealloc:
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UITextFieldTextDidChangeNotification" object:myTextField];
Я создал этот подкласс UITextFieldLimit:
- Поддерживается несколько текстовых полей
- Установить ограничение на длину текста
- Предотвращение пасты
- Отображает метку левых символов внутри текстового поля, скрывается, когда вы прекращаете редактирование.
- Анимация встряхивания, когда не осталось персонажей.
Возьмите UITextFieldLimit.h
и UITextFieldLimit.m
из этого репозитория GitHub:
https://github.com/JonathanGurebo/UITextFieldLimit
и начинаем тестировать!
Отметьте свой созданный раскадровкой UITextField и свяжите его с моим подклассом с помощью Identity Inspector:
Затем вы можете связать его с IBOutlet и установить лимит (по умолчанию 10).
Ваш файл ViewController.h должен содержать: (если вы не хотите изменять настройку, например ограничение)
#import "UITextFieldLimit.h"
/.../
@property (weak, nonatomic) IBOutlet UITextFieldLimit *textFieldLimit; // <--Your IBOutlet
Ваш файл ViewController.m должен @synthesize textFieldLimit
.
Установите ограничение длины текста в файле ViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[textFieldLimit setLimit:25];// <-- and you won't be able to put more than 25 characters in the TextField.
}
Надеюсь, этот класс тебе поможет. Удачи!
Этого должно быть достаточно для решения проблемы (замените 4 желаемым пределом). Просто не забудьте добавить делегата в IB.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return (newString.length<=4);
}
Используйте расширение ниже, чтобы установить максимальную длину символа для UITextField
и UITextView
.
Swift 4.0
private var kAssociationKeyMaxLength: Int = 0
private var kAssociationKeyMaxLengthTextView: 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)
addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
}
}
@objc func checkMaxLength(textField: UITextField) {
guard let prospectiveText = self.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
let substring = prospectiveText[..<indexEndOfText]
text = String(substring)
selectedTextRange = selection
}
}
UITextView
extension UITextView:UITextViewDelegate {
@IBInspectable var maxLength: Int {
get {
if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLengthTextView) as? Int {
return length
} else {
return Int.max
}
}
set {
self.delegate = self
objc_setAssociatedObject(self, &kAssociationKeyMaxLengthTextView, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
public func textViewDidChange(_ textView: UITextView) {
checkMaxLength(textField: self)
}
@objc func checkMaxLength(textField: UITextView) {
guard let prospectiveText = self.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
let substring = prospectiveText[..<indexEndOfText]
text = String(substring)
selectedTextRange = selection
}
}
Вы можете установить лимит ниже.
Я моделирую фактическую замену строки, которая вот-вот должна произойти, чтобы вычислить длину этой будущей строки:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if([newString length] > maxLength)
return NO;
return YES;
}
Существует универсальное решение для установки максимальной длины в Swift. С помощью IBInspectable вы можете добавить новый атрибут в Xcode Attribute Inspector.
import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {
@IBInspectable var maxLength: Int {
get {
guard let length = maxLengths[self]
else {
return Int.max
}
return length
}
set {
maxLengths[self] = newValue
addTarget(
self,
action: Selector("limitLength:"),
forControlEvents: UIControlEvents.EditingChanged
)
}
}
func limitLength(textField: UITextField) {
guard let prospectiveText = textField.text
where prospectiveText.characters.count > maxLength else {
return
}
let selection = selectedTextRange
text = prospectiveText.substringWithRange(
Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength))
)
selectedTextRange = selection
}
}
Версия Swift 3 // ***** Это НЕ будет работать со Swift 2.x! ***** //
Сначала создайте новый файл Swift: TextFieldMaxLength.swift, а затем добавьте код ниже:
import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {
@IBInspectable var maxLength: Int {
get {
guard let length = maxLengths[self]
else {
return Int.max
}
return length
}
set {
maxLengths[self] = newValue
addTarget(
self,
action: #selector(limitLength),
for: UIControlEvents.editingChanged
)
}
}
func limitLength(textField: UITextField) {
guard let prospectiveText = textField.text,
prospectiveText.characters.count > maxLength
else {
return
}
let selection = selectedTextRange
let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
text = prospectiveText.substring(to: maxCharIndex)
selectedTextRange = selection
}
}
а затем вы увидите в раскадровке новое поле (максимальная длина) при выборе любого текстового поля
если у вас остались вопросы, перейдите по этой ссылке: http://www.globalnerdy.com/2016/05/18/ios-programming-trick-how-to-use-xcode-to-set-a-text-fields-maximum-length-visual-studio-style/
Используя конструктор интерфейсов, вы можете связать и получить событие «Редактирование изменено» в любой из ваших функций. Теперь туда можно поставить чек на длину
- (IBAction)onValueChange:(id)sender
{
NSString *text = nil;
int MAX_LENGTH = 20;
switch ([sender tag] )
{
case 1:
{
text = myEditField.text;
if (MAX_LENGTH < [text length]) {
myEditField.text = [text substringToIndex:MAX_LENGTH];
}
}
break;
default:
break;
}
}
Следующий код похож на ответ больного, но правильно обрабатывает операции копирования и вставки. Если вы попытаетесь вставить текст, длина которого превышает лимит, следующий код усечет текст, чтобы он соответствовал лимиту, вместо того, чтобы полностью отказаться от операции вставки.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
static const NSUInteger limit = 70; // we limit to 70 characters
NSUInteger allowedLength = limit - [textField.text length] + range.length;
if (string.length > allowedLength) {
if (string.length > 1) {
// get at least the part of the new string that fits
NSString *limitedString = [string substringToIndex:allowedLength];
NSMutableString *newString = [textField.text mutableCopy];
[newString replaceCharactersInRange:range withString:limitedString];
textField.text = newString;
}
return NO;
} else {
return YES;
}
}
Чтобы заставить его работать с вырезанием и вставкой строк любой длины, я бы предложил изменить функцию на что-то вроде:
#define MAX_LENGTH 20
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSInteger insertDelta = string.length - range.length;
if (textField.text.length + insertDelta > MAX_LENGTH)
{
return NO; // the new string would be longer than MAX_LENGTH
}
else {
return YES;
}
}
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
}
guard
?
- person oddRaven; 07.04.2018
Swift 2.0 +
Прежде всего создайте класс для этого процесса. Назовем его StringValidator.swift.
Затем просто вставьте в него следующий код.
import Foundation
extension String {
func containsCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) != nil
}
func containsOnlyCharactersIn(matchCharacters: String) -> Bool {
let disallowedCharacterSet = NSCharacterSet(charactersInString: matchCharacters).invertedSet
return self.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
}
func doesNotContainCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) == nil
}
func isNumeric() -> Bool
{
let scanner = NSScanner(string: self)
scanner.locale = NSLocale.currentLocale()
return scanner.scanDecimal(nil) && scanner.atEnd
}
}
Теперь сохраните класс .....
Использование…
Теперь перейдите в свой класс viewController.swift и сделайте выходы текстового поля как ..
@IBOutlet weak var contactEntryTxtFld: UITextField! //First textfield
@IBOutlet weak var contactEntryTxtFld2: UITextField! //Second textfield
Теперь перейдите к методу shouldChangeCharactersInRange текстового поля и используйте его, как показано ниже.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if string.characters.count == 0 {
return true
}
let latestText = textField.text ?? ""
let checkAbleText = (latestText as NSString).stringByReplacingCharactersInRange(range, withString: string)
switch textField {
case contactEntryTxtFld:
return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5
case contactEntryTxtFld2:
return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5
default:
return true
}
}
Не забудьте установить протокол / методы делегата для текстовых полей.
Позвольте мне объяснить об этом ... Я использую простой процесс расширения строки, который я написал внутри другого класса. Теперь я просто вызываю эти методы расширения из другого класса, где они мне нужны, добавляя проверку и максимальное значение.
Возможности ...
- Он установит максимальный предел конкретного текстового поля.
- Он установит тип принимаемых ключей для конкретного текстового поля.
Типы ...
containsOnlyCharactersIn // Принимает только символы.
containsCharactersIn // Принимает комбинацию символов
doesNotContainsCharactersIn // Не принимает символы
Надеюсь, это помогло .... Спасибо ..
быстрый 3.0
Этот код работает нормально, когда вы вставляете строку, превышающую допустимое количество символов.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let str = (textView.text + text)
if str.characters.count <= 10 {
return true
}
textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
return false
}
Спасибо за ваши голоса. :)
Даю дополнительный ответ на основе @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)
}
}
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
}
//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
}
}
Это правильный способ обработки максимальной длины в UITextField, он позволяет клавише возврата выйти из текстового поля в качестве первого респондента и позволяет пользователю вернуться на место, когда они достигнут предела
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
int MAX_LENGHT = 5;
if([string isEqualToString:@"\n"])
{
[textField resignFirstResponder];
return FALSE;
}
else if(textField.text.length > MAX_LENGHT-1)
{
if([string isEqualToString:@""] && range.length == 1)
{
return TRUE;
}
else
{
return FALSE;
}
}
else
{
return TRUE;
}
}
Как насчет этого простого подхода. Он отлично работает для меня.
extension UITextField {
func charactersLimit(to:Int) {
if (self.text!.count > to) {
self.deleteBackward()
}
}
}
Потом:
someTextField.charactersLimit(to:16)
Другие ответы не относятся к случаю, когда пользователь может вставить длинную строку из буфера обмена. Если я вставлю длинную строку, она должна быть просто усечена, но показана. Используйте это в своем делегате:
static const NSUInteger maxNoOfCharacters = 5;
-(IBAction)textdidChange:(UITextField * )textField
{
NSString * text = textField.text;
if(text.length > maxNoOfCharacters)
{
text = [text substringWithRange:NSMakeRange(0, maxNoOfCharacters)];
textField.text = text;
}
// use 'text'
}
Получил до 1 строчки кода :)
Установите делегата текстового представления на «self», затем добавьте <UITextViewDelegate>
в свой .h и следующий код в свой .m .... вы можете настроить число «7» на то, что вы хотите, чтобы ваше МАКСИМАЛЬНОЕ количество символов было.
-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
return ((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length)>0);
}
Этот код учитывает ввод новых символов, удаление символов, выбор символов, затем ввод или удаление, выбор символов и вырезание, вставку в целом и выбор символов и вставку.
Выполнено!
В качестве альтернативы, еще один классный способ написать этот код с битовыми операциями был бы
-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
return 0^((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length));
}
Я открыл подкласс UITextField, STATextField , который предлагает эту функциональность (и многое другое) с помощью свойства maxCharacterLength
.
Теперь, сколько символов вы хотите, просто укажите значения
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 25) ? NO : YES;
}
Используйте здесь этот код. RESTRICTED_LENGTH - это длина, которую вы хотите ограничить для текстового поля.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == nameTF) {
int limit = RESTRICTED_LENGTH - 1;
return !([textField.text length]>limit && [string length] > range.length);
}
else
{
return YES;
}
return NO;
}
Я сделал это в Swift для ограничения в 8 символов при использовании цифровой клавиатуры.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
return !(textField.text?.characters.count == MAX_LENGTH && string != "")
}
Мне пришлось проверить строку! = "", Чтобы кнопка удаления работала на цифровой клавиатуре, иначе она не позволила бы удалить символы в текстовом поле после того, как она достигла своего максимального значения.
Для Xamarin:
YourTextField.ShouldChangeCharacters =
delegate(UITextField textField, NSRange range, string replacementString)
{
return (range.Location + replacementString.Length) <= 4; // MaxLength == 4
};
Я реализовал расширение UITextField, чтобы добавить к нему свойство maxLength.
Он основан на Xcode 6 IBInspectables, поэтому вы можете установить ограничение maxLength в построителе интерфейса.
Вот реализация:
UITextField + MaxLength.h
#import <UIKit/UIKit.h>
@interface UITextField_MaxLength : UITextField<UITextFieldDelegate>
@property (nonatomic)IBInspectable int textMaxLength;
@end
UITextField + MaxLength.m
#import "UITextField+MaxLength.h"
@interface UITextField_MaxLength()
@property (nonatomic, assign) id <UITextFieldDelegate> superDelegate;
@end
@implementation UITextField_MaxLength
- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//validate the length, only if it's set to a non zero value
if (self.textMaxLength>0) {
if(range.length + range.location > textField.text.length)
return NO;
if (textField.text.length+string.length - range.length>self.textMaxLength) {
return NO;
}
}
//if length validation was passed, query the super class to see if the delegate method is implemented there
if (self.superDelegate && [self.superDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
return [self.superDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
}
else{
//if the super class does not implement the delegate method, simply return YES as the length validation was passed
return YES;
}
}
- (void)setDelegate:(id<UITextFieldDelegate>)delegate {
if (delegate == self)
return;
self.superDelegate = delegate;
[super setDelegate:self];
}
//forward all non overriden delegate methods
- (id)forwardingTargetForSelector:(SEL)aSelector {
if ([self.superDelegate respondsToSelector:aSelector])
return self.superDelegate;
return [super forwardingTargetForSelector:aSelector];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
if ([self.superDelegate respondsToSelector:aSelector])
return YES;
return [super respondsToSelector:aSelector];
}
@end
Если ваша цель ограничения количества текста состоит в том, чтобы гарантировать, что текст поместится в UILabel в другом месте, я бы не использовал счетчик символов. Он не работает с некоторыми смайликами (попытка обрезать смайлики двойного размера, скорее всего, приведет к сбою вашего приложения). Это также проблема с некоторыми языками, такими как японский и китайский, которые имеют двухэтапный процесс ввода, когда простой счет просто не работает.
Я создал подкласс UITextField drop-in (MPC_CharacterLimitedTextField на github). Вы вводите ему ожидаемую ширину выходной метки, и он будет обрабатывать все языки, смайлики и проблемы с вставкой. Он соберет столько полных символов, сколько поместится на этикетке, независимо от количества символов. В проекте есть демонстрация, поэтому вы можете протестировать ее, чтобы убедиться, что она вам нужна. Надеюсь, это поможет любому, у кого были те же проблемы с длиной вывода, что и у меня.
Вы также можете сделать это с помощью NotificationCenter в Swift 4.
NotificationCenter.default.addObserver(self, selector: #selector(self.handleTextChange(recognizer:)), name: NSNotification.Name.UITextFieldTextDidChange, object: yourTextField)
@objc func handleTextChange(recognizer: NSNotification) {
//max length is 50 charater max
let textField = recognizer.object as! UITextField
if((textField.text?.count)! > 50) {
let newString: String? = (textField.text as NSString?)?.substring(to: 50)
textField.text = newString
}
}
Swift 4.2 и метод UITextFieldDelegate
Это работает для меня и ограничивает текстовое поле максимальным вводом 8 символов. Надеюсь, NSRange в конечном итоге будет изменен на Range, но пока я счастлив использовать NSString, поскольку создание Range из NSRange включает в себя работу с другим необязательным.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = textField.text ?? ""
let nsString = text as NSString
let newText = nsString.replacingCharacters(in: range, with: string)
return newText.count <= 8
}
Проблема с некоторыми из приведенных выше ответов: например, у меня есть текстовое поле, и я должен установить ограничение в 15 символов ввода, затем он останавливается после ввода 15-го символа. но они не позволяют удалить. То есть кнопка удаления тоже не работает. Поскольку я столкнулся с той же проблемой. Вышел с решением, данным ниже. Идеально подходит для меня
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(textField.tag==6)
{
if ([textField.text length]<=30)
{
return YES;
}
else if([@"" isEqualToString:string])
{
textField.text=[textField.text substringToIndex:30 ];
}
return NO;
}
else
{
return YES;
}
}
У меня есть текстовое поле, тег которого я установил "6", и я ограничил max char limit = 30; отлично работает в любом случае
Это ограничивает количество символов, но также убедитесь, что вы можете вставить в поле до максимального предела.
- (void)textViewDidChange:(UITextView *)textView
{
NSString* str = [textView text];
str = [str substringToIndex:MIN(1000,[str length])];
[textView setText:str];
if([str length]==1000) {
// show some label that you've reached the limit of 1000 characters
}
}
Немного помимо ответа на исходный вопрос и расширения ответа Фруо, вот расширения для обрезки строки пробелов до максимальной длины и использования этих расширений String для обрезки UITextField до максимальной длины:
// In String_Extensions.swift
extension String {
func trimmedString() -> String {
var trimmedString = self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
let components = trimmedString.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).filter { count($0) > 0 }
return " ".join(components)
}
func trimmedStringToMaxLength(maxLength: Int) -> String {
return trimmedString().substringToIndex(advance(startIndex, min(count(self), maxLength))).trimmedString()
}
}
// In UITextField_Extensions.swift
private var maxLengthDictionary = [UITextField : Int]()
private var textFieldMaxLength = 20
extension UITextField {
@IBInspectable var maxLength: Int {
get {
if let maxLength = maxLengthDictionary[self] {
return maxLength
} else {
return textFieldMaxLength
}
}
set {
maxLengthDictionary[self] = newValue < textFieldMaxLength + 1 ? newValue : textFieldMaxLength
}
}
func trimAndLimitToMaxLength() {
text = text.trimmedStringToMaxLength(maxLength)
}
}
let someTextField = UITextField()
let someString = " This is a string that is longer than allowable for a text field. "
someTextField.text = someString
someTextField.trimAndLimitToMaxLength()
println(someTextField.text) // Prints "This is a string tha"
let anotherTextField = UITextField()
anotherTextField.maxLength = 5
anotherTextField.text = someString
anotherTextField.trimAndLimitToMaxLength()
println(anotherTextField.text) // Prints "This"
trimAndLimitToMaxLength()
можно использовать в textFieldDidEndEditing(_:)
UITextFieldDelegate, чтобы пользователь мог вводить или вставлять более длинную, чем допустимую строку, а затем сокращать ее, а не просто обрезать ввод по максимальной длине. При этом я бы также установил стили текста с атрибутами, чтобы указать любую часть текста, выходящую за пределы допустимой длины (например, [NSBackgroundColorAttributeName : UIColor.redColor(), NSForegroundColorAttributeName : UIColor.whiteColor(), NSStrikethroughStyleAttributeName : NSNumber(int: 1)]
мы можем установить диапазон текстового поля вот так ..
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
int setrange = 20;
return !([textField.text length]>setrange && [string length] > range.length);
}
Для Swift 2.1+
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if (range.length + range.location > textField.text!.characters.count )
{
return false;
}
let newLength = textField.text!.characters.count + string.characters.count - range.length
return newLength <= 25
}
Надеюсь, это поможет
Я хочу добавить к ответу @sickp.
В его Swift
коде есть проблема, которая возникает с любым многобайтовым текстом (например, смайликами). NSRange
и String
в Swift
несовместимы, поэтому неприятно, что класс делегата объединяет их. Уловка состоит в том, чтобы просто преобразовать объекты String
в NSString
. Правильное решение, основанное на том, что написал @sickp, на самом деле таково:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentText = (textField.text as NSString?) ?? NSString()
let currentCharacterCount = currentText.length
if range.length + range.location > currentCharacterCount {
return false
}
let newLength = currentText.replacingCharacters(in: range, with: string).characters.count
return newLength <= 25
}
для Swift 3.1 или новее
сначала добавьте протокол UITextFieldDelegate
как: -
class PinCodeViewController: UIViewController, UITextFieldDelegate {
.....
.....
.....
}
после этого создайте свой UITextField и установите делегата
Полный опыт: -
import UIKit
class PinCodeViewController: UIViewController, UITextFieldDelegate {
let pinCodetextField: UITextField = {
let tf = UITextField()
tf.placeholder = "please enter your pincode"
tf.font = UIFont.systemFont(ofSize: 15)
tf.borderStyle = UITextBorderStyle.roundedRect
tf.autocorrectionType = UITextAutocorrectionType.no
tf.keyboardType = UIKeyboardType.numberPad
tf.clearButtonMode = UITextFieldViewMode.whileEditing;
tf.contentVerticalAlignment = UIControlContentVerticalAlignment.center
return tf
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(pinCodetextField)
//----- setup your textfield anchor or position where you want to show it-----
// after that
pinCodetextField.delegate = self // setting the delegate
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return !(textField.text?.characters.count == 6 && string != "")
} // this is return the maximum characters in textfield
}
Работа в Swift 5.2:
class AngListVC: UIViewController, UITextFieldDelegate {
@IBOutlet weak var angTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
angTextField.delegate = self
angTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let userText = angTextField.text ?? ""
var newText = ""
if range.length > 0 {
let txt = NSString(string: userText)
if txt.length > 0 {
newText = txt.replacingCharacters(in: range, with: "")
}
} else {
newText = userText + ""
}
return newText.count <= 3
}
@objc func textFieldDidChange(_ textField: UITextField) {
print("textFieldDidChange")
}
Swift 4.2+
реализуя UITextFieldDelegate
метод
ViewController:
class MyViewController: UIViewController { let MAX_LENGTH = 256 @IBOutlet weak var myTextField: UITextField! override viewDidLoad() { self.myTextField.delegate = self } }
Делегат:
extension MyViewController: UITextFieldDelegate { func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let userText = textView.text ?? "" var newText = "" if range.length > 0 { let txt = NSString(string: userText) if txt.length > 0 { newText = txt.replacingCharacters(in: range, with: text) } } else { newText = userText + text } return newText.count <= MAX_LENGTH } }
Я нашел это быстро и просто
- (IBAction)backgroundClick:(id)sender {
if (mytext.length <= 7) {
[mytext resignFirstResponder];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Too Big"
message:@"Please Shorten Name"
delegate:nil
cancelButtonTitle:@"Cancel"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
UIAlertView
s. Вы должны зарезервировать предупреждения для важных сообщений и просто запретить ввод, как в принятом ответе.
- person Dan Abramov; 28.12.2012