限制UITextView中的字符数

87

我提供一个文本视图来发布一些字符串。

我正在应用以下方法,以将字符数量限制为140个长度。

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
   return [[textView text] length] <= 140;
}

代码工作正常,除了第一个条件:退格键不起作用。假设我达到了140个字符的限制,这时方法会返回false,用户无法再插入更多的字符,但之后当我尝试删除一些字符时,文本视图表现得好像已被禁用。

所以问题是:"如何从textview.text中删除字符或重新启用文本视图?"


请查看此答案 - Hemang
@Hemang http://stackoverflow.com/a/41380869/2910061 - Ilesh P
18个回答

178
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    return textView.text.length + (text.length - range.length) <= 140;
}

这解释了用户删减文本、删除多个字符(例如选中后按下退格键)、高亮选择一段文本并粘贴更短或更长的字符串等情况。

Swift 4.0 版本

 func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    return textView.text.count + (text.count - range.length) <= 140
}

这是一个IBAction吗?当用户输入时,我该如何将其连接到相关的TextView上? - learner
1
必须将您的视图控制器设置为UITextViewDelegate,然后将文件所有者连接到文本视图的委托。 - Tim
我认为提出一个跟进问题会更公平:我在同一个控制器中有两个需要字符限制的UITextviews,遇到了问题。你能帮忙吗?http://stackoverflow.com/questions/25272413/limit-number-of-characters-user-may-inter-into-multiple-uitextviews - learner
这应该被标记为正确的响应。谢谢。 - Hernan Arber
如果您粘贴的文本太长而无法适应(因此将返回“false”),然后尝试撤消操作,这将导致崩溃。 - Raimundas Sakalauskas

68
您应该寻找一个空字符串,正如苹果参考文献所述。
如果用户按下删除键,则范围的长度为1,一个空字符串对象将替换该单个字符。
我认为您实际要做的检查应该是像这样的 [[textView text] length] - range.length + text.length > 140,以考虑剪切/粘贴操作。

谢谢,但可以更具体一些吗?我无法理解苹果的技术规格。 - harshalb
告诉我在第一个条件中应该放什么。我已经搜索了将近4个小时。 - harshalb
9
我认为你实际想要进行的检查是类似于[[textView text] length] - range.length + text.length > 140的,以考虑剪切/粘贴操作。 - David Gelhar
3
[[textView text] length] - range.length + text.length > 140 应该改为 [[textView text] length] - range.length + text.length < 140。 - Kuzon
Kuzon,如果你将true作为默认返回值,并且想在超过140个字符限制时返回false,则需要进行判断。 - stone
在这种情况下,您还将计算换行符...我更喜欢这样做:NSMutableString *newString = [textView.text mutableCopy]; [newString replaceCharactersInRange:range withString:text];如果[newString length] <= 140,则可以执行以下操作...如果您不想计算换行符,则可以简单地操作newString... - Marco Cattai

19

对于Swift 4:

//MARK:- TextView Delegate
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    //300 chars restriction
    return textView.text.count + (text.count - range.length) <= 300
}

10

但是您也可以使用以下有效代码...

- (void)textViewDidChange:(UITextView *)textView{

    NSInteger restrictedLength=140;

    NSString *temp=textView.text;

    if([[textView text] length] > restrictedLength){
        textView.text=[temp substringToIndex:[temp length]-1];
    }
}

通常不是在设置后编辑某些内容的首选方式。最好在“shouldChangeCharactersInRange”中检查以防止文本被编辑。 - Benjamin Piette

10

限制溢出,而非整个文本!

...shouldChangeTextInRange...委托方法中返回false,实际上是限制了整个文本,并且处理以下情况可能非常困难:

  • 复制和粘贴
  • 选择文本区域并进行编辑
  • 使用自动建议
  • 使用语音输入(语音命令或听写)

所以你可以:

只需限制文本溢出即可!

通过删除额外字符:

textView.text = String(textView.text.prefix(140))

只需将此代码放入textViewtextField操作中,并使用.editingChanged事件,即可实现即时执行!


4
把这段代码放在UITextView代理方法中的func textViewDidChange(_ textView: UITextView) {...}里非常有效,可以很好地解决只截取长贴文末尾的问题。 - Josselin

7

使用Swift 5和iOS 12,尝试以下实现UITextViewDelegate协议的一部分的textView(_:shouldChangeTextIn:replacementText:)方法:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    guard let rangeOfTextToReplace = Range(range, in: textView.text) else {
        return false
    }
    let substringToReplace = textView.text[rangeOfTextToReplace]
    let count = textView.text.count - substringToReplace.count + text.count
    return count <= 10
}

以下是需要翻译的内容:
  • 这段代码最重要的部分是将 range (NSRange) 转换为 rangeOfTextToReplace (Range<String.Index>)。请参考此视频教程,了解为什么这种转换很重要。
  • 为使这段代码正常工作,您还应该将 textFieldsmartInsertDeleteType 值设置为 UITextSmartInsertDeleteType.no。这将防止在进行粘贴操作时可能插入(不必要的)额外空格。

下面是完整的示例代码,展示了如何在 UIViewController 中实现 textView(_:shouldChangeTextIn:replacementText:)

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    @IBOutlet var textView: UITextView! // Link this to a UITextView in Storyboard

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.smartInsertDeleteType = UITextSmartInsertDeleteType.no
        textView.delegate = self
    }

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        guard let rangeOfTextToReplace = Range(range, in: textView.text) else {
            return false
        }
        let substringToReplace = textView.text[rangeOfTextToReplace]
        let count = textView.text.count - substringToReplace.count + text.count
        return count <= 10
    }

}

5

Swift:

// MARK: UITextViewDelegate

let COMMENTS_LIMIT = 255

func textView(textView: UITextView,  shouldChangeTextInRange range:NSRange, replacementText text:String ) -> Bool {
    return count(comments.text) + (count(text) - range.length) <= COMMENTS_LIMIT;
}

在 Swift 1.2 中,countElements 已被 count 取代。 - Tim Windsor Brown
1
在Swift 2中,您需要使用textView.text.characters.count或任何您想要的编码:https://developer.apple.com/swift/blog/?id=30 - Heckscheibe

4
使用这个。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{

    int limit = 139;

    return !([textField.text length]>limit && [string length] > range.length);

}

这只会输入140个字符,如果需要可以删除它们。


这段文字与IT技术无关。

2

虽然我需要一个 if-else 条件,所以这对我有用:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    BOOL status = textView.text.length + (text.length - range.length) <= 15;
    if (status)
    {
        [self.btnShare setEnabled:YES];
        [self.btnShare setAlpha:1];
    }
    else
    {
        [self.btnShare setEnabled:NO];
        [self.btnShare setAlpha:0.25];
    }
    return status;
}

最初按钮被设置为禁用状态。但是如果你希望用户不能发布空的测试内容,只需在按钮单击时添加一个条件:

- (void)btnShare_click:(id)sender
{
    NSString *txt = [self.txtShare.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    if ([txt length] == 0)
    {
        [self.btnShare setEnabled:NO];
        [self.btnShare setAlpha:0.25f];
        [[[UIAlertView alloc]initWithTitle:nil message:@"Please enter some text to share." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
        return;
    }
    .
    .
    .
    .
    .
    .
    // rest of your code
}

2

试一试:

 func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    print("chars \(textView.text.count) \( text)")

    if(textView.text.count > 20 && range.length == 0) {
        print("Please summarize in 20 characters or less")
        return false
    }
    return true
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接