ios 设置 UITextField 的最大字符长度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/433337/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:31:14  来源:igfitidea点击:

Set the maximum character length of a UITextField

iosobjective-ccocoa-touchuitextfield

提问by Domness

How can I set the maximum amount of characters in a UITextFieldon the iPhone SDK when I load up a UIView?

如何设置的字符的最大数量UITextField的iPhone SDK当我加载了UIView

回答by sickp

While the UITextFieldclass has no max length property, it's relatively simple to get this functionality by setting the text field's delegateand implementing the following delegate method:

虽然UITextField该类没有最大长度属性,但通过设置文本字段delegate并实现以下委托方法来获得此功能相对简单:

Objective-C

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

Before the text field changes, the UITextField asks the delegate if the specified text shouldbe changed. The text field has not changed at this point, so we grab it's current length and the string length we're inserting (either through pasting copied text or typing a single character using the keyboard), minus the range length. If this value is too long (more than 25 characters in this example), return NOto prohibit the change.

在文本字段更改之前, UITextField 会询问委托是否更改指定的文本。此时文本字段没有改变,所以我们获取它的当前长度和我们插入的字符串长度(通过粘贴复制的文本或使用键盘输入单个字符)减去范围长度。如果这个值太长(本例中超过 25 个字符),返回NO禁止更改。

When typing in a single character at the end of a text field, the range.locationwill be the current field's length, and range.lengthwill be 0 because we're not replacing/deleting anything. Inserting into the middle of a text field just means a different range.location, and pasting multiple characters just means stringhas more than one character in it.

在文本字段的末尾输入单个字符时,range.location将是当前字段的长度,并且range.length为 0,因为我们没有替换/删除任何内容。插入到文本字段的中间只是意味着一个不同的range.location,而粘贴多个字符只是意味着其中string有多个字符。

Deleting single characters or cutting multiple characters is specified by a rangewith a non-zero length, and an empty string. Replacement is just a range deletion with a non-empty string.

删除单个字符或剪切多个字符由range具有非零长度和空字符串的 a指定。替换只是带有非空字符串的范围删除。

A note on the crashing "undo" bug

关于崩溃的“撤消”错误的说明

As is mentioned in the comments, there is a bug with UITextFieldthat can lead to a crash.

正如评论中提到的,有一个UITextField可能导致崩溃的错误。

If you paste in to the field, but the paste is prevented by your validation implementation, the paste operation is still recorded in the application's undo buffer. If you then fire an undo (by shaking the device and confirming an Undo), the UITextFieldwill attempt to replace the string it thinksit pasted in to itself with an empty string. This will crash because it never actuallypasted the string in to itself. It will try to replace a part of the string that doesn't exist.

如果您粘贴到字段中,但您的验证实现阻止了粘贴,则粘贴操作仍会记录在应用程序的撤消缓冲区中。如果您随后触发撤消(通过摇动设备并确认撤消),UITextField它将尝试用空字符串替换它认为粘贴到自身的字符串。这会崩溃,因为它实际上从未将字符串粘贴到自身中。它将尝试替换不存在的字符串的一部分。

Fortunately you can protect the UITextFieldfrom killing itself like this. You just need to ensure that the range it proposes to replace doesexist within its current string. This is what the initial sanity check above does.

幸运的是,您可以保护它UITextField免于像这样杀死自己。您只需要确保它建议替换的范围确实存在于其当前字符串中。这就是上面的初始健全性检查所做的。

swift 3.0 with copy and paste working fine.

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
    }

Hope it's helpful to you.

希望对你有帮助。

回答by frouo

Swift 4

斯威夫特 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: memory leak issue fixed.

编辑:修复了内存泄漏问题。

enter image description here

在此处输入图片说明

回答by Domness

Thank you august! (Post)

谢谢八月!(发布)

This is the code that I ended up with which works:

这是我最终使用的代码:

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

回答by Jmini

To complete Augustanswer, an possible implementation of the proposed function (see UITextField's delegate).

要完成August 的回答,建议函数的可能实现(请参阅UITextField 的委托)。

I did not test domnesscode, but mine do not get stuck if the user reached the limit, and it is compatible with a new string that comes replace a smaller or equal one.

我没有测试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);
}

回答by August

You can't do this directly - UITextFieldhas no maxLengthattribute, but you can set the UITextField'sdelegate, then use:

您不能直接执行此操作 -UITextField没有maxLength属性,但您可以设置UITextField's委托,然后使用:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

回答by Vincent

Often you have multiple input fields with a different length.

通常,您有多个不同长度的输入字段。

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

回答by Martin Pilkington

The best way would be to set up a notification on the text changing. In your -awakeFromNibof your view controller method you'll want:

最好的方法是在文本更改时设置通知。在您-awakeFromNib的视图控制器方法中,您需要:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(limitTextField:) name:@"UITextFieldTextDidChangeNotification" object:myTextField];

Then in the same class add:

然后在同一个类中添加:

- (void)limitTextField:(NSNotification *)note {
    int limit = 20;
    if ([[myTextField stringValue] length] > limit) {
        [myTextField setStringValue:[[myTextField stringValue] substringToIndex:limit]];
    }
}

Then link up the outlet myTextFieldto your UITextFieldand it will not let you add any more characters after you hit the limit. Be sure to add this to your dealloc method:

然后将插座连接myTextField到您的插座UITextField,它不会让您在达到限制后添加更多字符。请务必将此添加到您的 dealloc 方法中:

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UITextFieldTextDidChangeNotification" object:myTextField];

回答by Jonathan Gurebo

I created thisUITextFieldLimit subclass:

我创建了这个UITextFieldLimit 子类:

  • Multiple textfields supported
  • Set the text length limit
  • Paste prevention
  • Displays a label of left characters inside the textfield, get hidden when you stop editing.
  • Shake animation when no characters left.
  • 支持多个文本字段
  • 设置文本长度限制
  • 防糊
  • 在文本字段内显示左侧字符的标签,停止编辑时隐藏。
  • 当没有角色离开时摇动动画。

Grab the UITextFieldLimit.hand UITextFieldLimit.mfrom this GitHub repository:

抓住UITextFieldLimit.hUITextFieldLimit.m从该GitHub的仓库:

https://github.com/JonathanGurebo/UITextFieldLimit

https://github.com/JonathanGurebo/UITextFieldLimit

and begin to test!

并开始测试!

Mark your storyboard-created UITextField and link it to my subclass using the Identity Inspector:

标记您的故事板创建的 UITextField 并使用身份检查器将其链接到我的子类:

Identity Inspector

身份检查员

Then you can link it to an IBOutlet and set the limit(default is 10).

然后您可以将其链接到 IBOutlet 并设置限制(默认为 10)。



Your ViewController.h file should contain: (if you wan't to modify the setting, like the limit)

你的 ViewController.h 文件应该包含:(如果你不想修改设置,比如限制)

#import "UITextFieldLimit.h"

/.../

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


Your ViewController.m file should @synthesize textFieldLimit.

您的 ViewController.m 文件应该是@synthesize textFieldLimit.



Set the text length limit in your ViewController.m file:

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

Hope the class helps you. Good luck!

希望课对你有帮助。祝你好运!

回答by Nishant

This should be enough to solve the problem (replace 4 by the limit u want). Just make sure to add delegate in IB.

这应该足以解决问题(用你想要的限制替换 4)。只要确保在 IB 中添加委托。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
     NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
     return (newString.length<=4);
}

回答by COVID19

Use below extension to set the maximum character length of a UITextFieldand UITextView.

使用下面的扩展名设置 aUITextField和的最大字符长度UITextView

Swift 4.0

斯威夫特 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
        }
    }

You can set limit below.

您可以在下面设置限制。

enter image description here

在此处输入图片说明