Как я могу установить максимальное количество символов в UITextField в iPhone SDK при загрузке UIView?
Возможный дубликат Установите максимальную длину символа UITextField в Swift





Вы не можете сделать это напрямую - UITextField не имеет атрибута максимальная длина, но вы можете установить делегат UITextField's, а затем использовать:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Я согласен, это лучший способ продвинуться вперед, но он остается чем-то вроде взлома. Отправьте в Apple отчет об ошибке, если вы хотите увидеть свойство для длины текста. Меня это тоже определенно интересует.
@avocade, это не взлом: это пример, в котором вам нужно написать базовый код фреймворка, который Apple должна была сделать за вас. В iOS SDK есть МНОЖЕСТВО примеров этого.
Лучше всего настроить уведомление об изменении текста. В вашем -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];
Хотя я сделал это для удаления ошибок> myTextField.text = [myTextField.text substringToIndex: limit];
Спасибо, август! (Почта)
Вот код, который у меня работает:
#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;}
}
К сожалению, это решение не может остановить копирование и вставку пользователей в текстовое поле, что позволяет им обойти ограничение. Ответ Sickpea правильно справляется с этой ситуацией.
Что происходит с людьми, у которых оператор if возвращает NO или YES? Попробуйте это: return! (TextField.text.length> = MAX_LENGTH && range.length == 0);
или это return textField.text.length < MAX_LENGTH || range.length != 0;
Чтобы завершить ответ август, возможная реализация предложенной функции (см. Делегат UITextField).
Я не тестировал код домина, но мой не застревает, если пользователь достиг предела, и он совместим с новой строкой, которая заменяет меньшую или равную.
-(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);
}
Чтобы заставить его работать с вырезанием и вставкой строк любой длины, я бы предложил изменить функцию на что-то вроде:
#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;
}
}
Хотя класс 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;
}
Быстрый
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 от подобного самоубийства. Вам просто нужно убедиться, что диапазон, который он предлагает для замены делает, существует в его текущей строке. Это то, что делает приведенная выше начальная проверка работоспособности.
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
}
Надеюсь, это поможет вам.
Отлично работает ... Как для добавления / удаления.
Как я могу установить только один UITextView на моем экране? Когда я добавляю его в свой класс, он применяется ко всем текстовым представлениям.
Нашел решение, заключив эти две строки в if (textField == _ssn) {} и добавив return YES; в конце метода, что позволит всем остальным UITextFields принимать текст без каких-либо ограничений. Отлично!
Очень хороший ответ. Я хотел бы видеть тот, который принимает как можно больше текста, вместо того, чтобы не разрешать его (например, если они попытаются добавить 10 символов, а осталось 9, добавьте первые 9) - например, элементы управления редактированием Windows работают. Но так как я не хочу делать эту работу сам, вы получите мой голос, сэр! :) (надеюсь, Apple скоро добавит это)
Хороший ответ, но тернарный оператор не нужен; можно было просто поставить return newLength <= 25;
Мне это тоже пригодилось. Но если у меня есть 2 разных текстовых поля с разным размером? как я могу это сделать?
Вау, спасибо большое!! В этом примере максимальная длина устанавливается как 25 символов (25 включительно) только для справки.
Что, если вы просто хотите, чтобы текст не выходил за рамки текстового поля; не все символы одинаковой ширины, верно?
@Morkrom Вы правы, взгляните на этот длинный пост про NSString и Unicode
Если у кого-то возникнут трудности, убедитесь, что делегат UITextField установлен на self и что <UITextFieldDelegate> установлен в файле заголовка.
Отличный пример !! Спасибо! @sickp
Как упоминает @bcherry, действительно есть ошибка отмены - протестировано с UITextField на iPad iOS 8.1. (+1 к комментарию). Может ли автор что-нибудь добавить по этому поводу, так как это самый популярный ответ? Я счастлив сделать правку, но мне регулярно отказывают! :-)
Я добавил чек на сбой и некоторые заметки о нем, взятые отсюда.
В системе есть еще одна ошибка: автокоррекция / прогноз обходит метод делегата -textField:shouldChangeCharactersInRange:replacementString. Я думаю, что для полноты ответа об этом стоит упомянуть.
Этот метод не может предотвратить ввод текста пользователем из автоматического предложения Apple над клавиатурой.
@bherry В Swift проверка случая отмены, похоже, нарушает ввод эмодзи. Разве счетчик (textField.text) на самом деле не должен быть count (textField.text.utf16), чтобы соответствовать отчету objc / uikit в диапазоне (по сравнению с вариантом подсчета строк в Swift)?
В Swift 2.0 count(textField.text) должен быть textField.text?.characters.count.
Как вызвать этот метод в objc?
Для кода Swift сравнение textField.text? .Characters.count с диапазоном добавит ошибку при использовании символов Emoji. Вы должны использовать textField.text? .Utf16.count, чтобы он работал, как описано.
Ошибка все еще существует в последних версиях iOS? Я не могу воспроизвести это на своем iPhone с 10.2 и в симуляторе с 8.4.
Извините, я перепроверил, и да, он все еще существует в обоих моих случаях. Я не смог сначала воспроизвести его, потому что, если вы закомментируете «код обхода ошибки», он обнаружит другую проблему, потому что newLength без знака, но результат может быть отрицательным. Таким образом, отрицательные значения становятся очень большими положительными числами. И сравнение возвращает NO, что скрывает ошибку.
Swift 3: func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
Это быстро не удается при удалении последнего символа, если он состоит из нескольких байтов (например, range.length> 1). К сожалению, классы NSRange и String не очень совместимы, поэтому вы можете столкнуться с подобными проблемами. Вам нужно преобразовать в объекты NSString. Я выложу решение.
Парень, было ли обновлено решение "Swift 3.0", указанное выше, для решения проблемы "удаления последнего символа"? Также я заметил, что решение «Swift 3.0» предназначено для textView вместо textField?
это ПОЧТИ ДЕСЯТЬ ЛЕТ НЕ ДАТА. хе! теперь это банально: stackoverflow.com/a/38306929/294884
Подскажите, как правильно ограничить максимальную длину ввода текста? т.е. если я ограничиваю ввод до 3 символов и пытаюсь ввести «で で で», что достигается, когда я нажимаю кнопки клавиатуры «dedede» (каждый «de» преобразуется в «で»), то я не могу ввести последний символ, потому что моя функция проверки считает, что это 4 символа. Вот моя функция проверки: -(BOOL)textField:(UITextField*)tf shouldChangeCharactersInRange:(NSRange)r replacementString:(NSString*)s {return [tf.text stringByReplacingCharactersInRange:r withString:s].length <= 3;} Это можно воспроизвести на японском языке - клавиатура ромадзи
решение - сокращение длины строки в текстовом поле, редактирование закончилось, поэтому авторское решение не обрабатывает этот случай для клавиатуры с японскими ромадзи.
Предположим, у меня есть 2 текстовых поля. Для обоих требуется разный максимальный лимит символов, для одного требуется 10 символов, а для другого - 20 символов. В таком случае, какой подход мне нужно придерживаться. Есть ли способ сделать константу (25 в вашем коде) динамической?
чтобы всегда иметь возможность удалить текст в случае, если в текстовом поле уже был текст, превышающий допустимую длину, я заменил `` swift return newLength <= 25 '' на `` `` swift return newLength <= 25 || newLength <currentCharacterCount ``, который устранит проблему, при которой пользователь не сможет удалить программно назначенный текст, превышающий maxLenght
Я нашел это быстро и просто
- (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];
}
}
Apple не одобряет такое использование UIAlertView. Вы должны зарезервировать предупреждения для важных сообщений и просто запретить ввод, как в принятом ответе.
Неправильный способ! --- Пользователь узнает о размере ввода после вставки полной строки!
Используя конструктор интерфейсов, вы можете связать и получить событие «Редактирование изменено» в любой из ваших функций. Теперь там можно поставить чек на длину
- (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 {
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if ([newString length] > maxLength)
return NO;
return YES;
}
Этого должно быть достаточно для решения проблемы (замените 4 желаемым пределом). Просто не забудьте добавить делегата в IB.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return (newString.length<=4);
}
Часто у вас есть несколько полей ввода разной длины.
- (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
}
}
Другие ответы не относятся к случаю, когда пользователь может вставить длинную строку из буфера обмена. Если я вставлю длинную строку, она должна быть только усечена, но показана. Используйте это в своем делегате:
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'
}
Это правильный способ обработки максимальной длины в 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;
}
}
Теперь, сколько символов вы хотите, просто укажите значения
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 25) ? NO : YES;
}
Получил до 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));
}
Проблема с некоторыми из приведенных выше ответов: Например, у меня есть текстовое поле, и я должен установить ограничение в 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; отлично работает в любом случае
Я создал подкласс это 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.
}
Надеюсь, этот класс тебе поможет. Удачи!
Для небольшой потребности в ограничении символов, я думаю, добавление вашего класса было бы излишним.
Тем не менее усилия оценены.
(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if ([txt_name.text length]>100)
{
return NO;
}
return YES;
}
мы можем установить диапазон текстового поля вот так ..
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
int setrange = 20;
return !([textField.text length]>setrange && [string length] > range.length);
}
Это ограничивает количество символов, но также убедитесь, что вы можете вставить в поле до максимального предела.
- (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
}
}
Следующий код похож на ответ больного, но правильно обрабатывает операции копирования и вставки. Если вы попытаетесь вставить текст, длина которого превышает лимит, следующий код усечет текст, чтобы он соответствовал лимиту, вместо того, чтобы полностью отказаться от операции вставки.
- (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;
}
}
Я реализовал расширение 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
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
}
}
Обновлено: исправлена проблема с утечкой памяти.
Отличная идея, Фруо! Я расширил его в своем ответе, чтобы переместить обрезку maxLength в расширение String, чтобы его также можно было использовать для таких вещей, как экземпляры UITextView, и добавить удобную функцию для использования преимуществ этих расширений String в расширении UITextField.
Разве эта глобальная переменная не создает утечки памяти, удерживая ссылки на все текстовые представления (которые ссылаются на супервизоры до root-)
@Ixx Я отредактировал, чтобы исправить проблему с утечкой памяти, на которую вы указали + swift 3. Спасибо.
самый красивый способ добиться этого! Спасибо
может ли кто-нибудь предоставить мне его объективную версию
Мне нужна такая же максимальная длина, добавленная в объект инспектора атрибутов c
Неординарное решение ❤️
Великолепное решение! Большое спасибо за то, что поделились?
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField.text.length >= 50) {
return NO;
}
return YES;
}
Это не заставит вас ввести символы больше или равные 50.
Немного помимо ответа на исходный вопрос и расширения ответа Фруо, вот расширения для обрезки строки пробелов до максимальной длины и использования этих расширений 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)]
Разве глобальный словарь не создает утечки памяти, удерживая ссылки на все текстовые представления (которые ссылаются на супервизоры до root-)
Я открыл исходный код подкласса UITextField, STATextField, который предлагает эту функциональность (и многое другое) с помощью свойства maxCharacterLength.
Используйте здесь этот код. 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 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
}
Надеюсь, поможет
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 // Не принимает символы
Надеюсь, это помогло .... Спасибо..
Я сделал это в 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
};
Для установки максимальной длины в 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
}
}
Чистое и идеальное решение
Сохранение UITextField в глобальном поле сохранит их в памяти даже после закрытия UIViewController. Это утечка памяти. Не используйте этот метод.
Версия 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/
Предупреждение, эта глобальная переменная создает утечки памяти, удерживая ссылки на все текстовые представления.
Если ваша цель ограничения количества текста состоит в том, чтобы гарантировать, что текст поместится в UILabel в другом месте, я бы не использовал счетчик символов. Он не работает с некоторыми смайликами (попытка обрезать смайлики двойного размера, скорее всего, приведет к сбою вашего приложения). Это также проблема с некоторыми языками, такими как японский и китайский, которые имеют двухэтапный процесс ввода, когда простой счет просто не работает.
Я создал подкласс UITextField (MPC_CharacterLimitedTextField на github). Вы вводите ему ожидаемую ширину выходной метки, и он будет обрабатывать все языки, смайлики и проблемы с вставкой. Он соберет столько полных символов, сколько поместится на этикетке, независимо от количества символов. В проекте есть демонстрация, поэтому вы можете протестировать ее, чтобы убедиться, что она вам нужна. Надеюсь, это поможет любому, у кого были те же проблемы с длиной вывода, что и у меня.
Этот код работает нормально, когда вы вставляете строку, превышающую допустимое количество символов.
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
}
Спасибо за ваши голоса. :)
UITextField, а не UITextView.
Я хочу добавить к ответу @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
}
Даю дополнительный ответ на основе @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
}
}
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?
проверьте, равен ли текст нулю, если хотите, вы также можете использовать if @oddRaven
Вы также можете сделать это с помощью 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
}
}
Используйте расширение ниже, чтобы установить максимальную длину символа для 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
}
}
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
}
}
Вы можете установить лимит ниже.
лучший ответ на сегодняшний день, большое спасибо, отличное решение, когда есть много текстовых полей, которым нужна разная длина
Действительно отличное решение для ограничения ввода текста в текстовое поле и текстовое поле. Сохраните строки кода и время для разработчика ... :)
Это работает лучше, чем другие найденные мной решения. Например, если у вас есть смайлы в текстовом поле, другие найденные мной расширения при редактировании переходят в конец строки. Но ваш код этого не делает. Спасибо!
Как насчет этого простого подхода. Он отлично работает для меня.
extension UITextField {
func charactersLimit(to:Int) {
if (self.text!.count > to) {
self.deleteBackward()
}
}
}
Потом:
someTextField.charactersLimit(to:16)
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
}
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
}
}
Это не компилируется
@ Лукас, правда? Этот код взят из реального проекта. Вам следует попробовать еще раз.
Работа в 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")
}
этот невероятно старый ответ очень устарел - теперь ответ тривиален: stackoverflow.com/a/38306929/294884