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

Как я могу установить максимальное количество символов UITextField на iPhone SDK, когда я загружаю UIView?

30 ответов


С UITextField класс не имеет свойства max length, относительно просто получить эту функциональность, установивdelegate и реализация следующего метода делегата:

С

- (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?.characters.count ?? 0
    if (range.length + range.location > currentCharacterCount){
        return false
    }
    let newLength = currentCharacterCount + string.characters.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
    }

надеюсь, это полезно для вас.


спасибо август! (в должности)

Это код, который я закончил, с которым работает:

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

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

Edit: Исправлена проблема с утечкой памяти.

enter image description here


завершить ответ, возможная реализация предложенной функции (см. делегат 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


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

- (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 файл должен содержать: (если вы не хотите изменять настройку, например limit)

#import "UITextFieldLimit.h"

/.../

@property (weak, nonatomic) IBOutlet UITextFieldLimit *textFieldLimit; // <--Your IBOutlet

Ваш ViewController.файл м @synthesize textFieldLimit.


Установите ограничение длины текста в ViewController.файл м:

- (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 на предел u хотите). Просто не забудьте добавить делегат в 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 {

    NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if([newString length] > maxLength)
       return NO;

    return YES;
}

версия Swift 3 //***** Это не будет работать с Swift 2.x! ***** / /

сначала создайте новый файл Swift: TextFieldMaxLength.быстрый, а затем добавьте код ниже:

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/


С помощью Interface builder вы можете связать и получить событие для "редактирования изменено" в любой из ваших функций. Теперь там можно поставить чек на длину

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

}

следующий код аналогичен ответа sickp, но ручки правильно копипастить операций. При попытке вставить текст, который длиннее предела, следующий код усечет текст, чтобы соответствовать пределу, вместо того, чтобы полностью отказаться от операции вставки.

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

чтобы заставить его работать с cut & paste строк любой длины, я бы предложил изменить функцию на что-то вроде:

#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. По IBInspectable вы можете добавить новый атрибут в Инспектор атрибутов Xcode.enter image description here

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 2.0+

прежде всего создайте класс для этого процесса. Назовем его StringValidator.быстрый.

затем просто вставьте следующий код внутри него.

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
}

}

Теперь сохраните класса.....

использование..

Теперь goto ваш viewController.swift класс и сделать выходы вашего textfield, как..

@IBOutlet weak var contactEntryTxtFld: UITextField! //First textfield
@IBOutlet weak var contactEntryTxtFld2: UITextField!   //Second textfield

Теперь goto метод 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
    }

}

не забудьте установить протокол делегата / методы textfields.

позвольте мне объяснить об этом... Я использую простой процесс расширения строки, который я написал внутри другого класса. Теперь я просто вызываю эти методы расширения из другого класса, где они мне нужны, добавив check и maximum value.

функции...

  1. он установит максимальный предел определенного объект TextField.
  2. он установит тип принятых ключей для определенного текстового поля.

типы...

containsOnlyCharactersIn / / принимает только символы.

containsCharactersIn / / принимает комбинацию символов

doesNotContainsCharactersIn / / не принимает символы

надеюсь, что это помогло.... Спасибо..


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
    }

Спасибо за ваши голоса. :)


это правильный способ обработки максимальной длины в 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;
    }
}

Для Xamarin:

YourTextField.ShouldChangeCharacters = 
delegate(UITextField textField, NSRange range, string replacementString)
        {
            return (range.Location + replacementString.Length) <= 4; // MaxLength == 4
        };

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
}

другие ответы не обработать случай, где пользователь может вставить длинную строку из буфера обмена. Если я вставляю длинную строку, она должна быть просто усечена, но показана. Используйте это в своем делегате:

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 строки кода:)

набор делегировать свой текст на "Я" тогда добавить <UITextViewDelegate> в вашей .H и следующий код в ваш .м. ... вы можете настроить число "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-длина, которую вы хотите ограничить для textfield.

   - (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 != "")
}

Я должен был проверить строку != "", чтобы кнопка "Удалить" работала на цифровой клавиатуре, иначе она не позволит удалять символы в текстовом поле после достижения максимального значения.


я реализовал расширение 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.м

#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

Я даю дополнительный ответ на основе @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
    }

}

проблема с некоторым из ответов, приведенных выше, например, у меня есть текстовое поле, и я должен установить предел ввода 15 символов, затем он останавливается после ввода 15-го символа. но они не позволяют удалить. То есть кнопка delete также не работает. Как я столкнулся с той же проблемой. Вышел с решением, приведенным ниже. Работает идеально подходит для меня

- (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" и я ограничил максимальный предел char = 30 ; работать отлично во всех случаях


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