0

对于我正在编写的 iOS 应用程序,我使用的是 UITextView,用户可以在其中插入有限的文本。

对于 textview 有 2 个限制:

  1. 行不能超过 30 个字符
  2. UITextView 中只能有 20 行文本。

所以简而言之,最多是 20 行,每行 30 个字符。

当用户在 UITextView 中键入一些文本并且当前句子是 30 个字符时,我希望它自动插入一个新行\n(在该行的最后一个单词之前)并强制最后一个单词和光标到下面的行。

当用户有 20 行 30 个字符(或者更简单地说:20 行,最后一行 30 个字符)时,我希望输入被阻止。

现在,其中大部分都相当“简单”,但我的代码没有考虑边界情况,比如在前面的行中插入文本。

我查看了来自 Apple 的文档,但我找不到一种方法来实际强制在 UITextView 上进行这种自动换行。

我的尝试是在shouldChangeTextInRange委托方法中处理所有这些(使代码更加冗长,因此更易于阅读)。

#define MAX_LENGTH_LINE 30
#define MAX_LENGTH_ROWS 20

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    // Check for backspaces, they should always be allowed?
    if ([text length] == 0 && ![text isEqualToString:@"\n"])
        return YES;

    NSArray* lines = [textView.text componentsSeparatedByString:@"\n"];

    // Check if there are a maximum of lines and the last line is already maxed out
    NSString* lastLine = [lines objectAtIndex:[lines count] - 1];

    if (([lines count] == MAX_LENGTH_ROWS) &&
        (lastLine != nil) &&
        ([lastLine length] > MAX_LENGTH_LINE) &&
        ([text length] > 0))
        return NO;


    if ((lastLine != nil) &&
        ([lastLine length] > MAX_LENGTH_LINE))
    {
        NSRange range = [textView.text rangeOfString:@" " options:NSBackwardsSearch];
        NSRange breakRange = [textView.text rangeOfString:@"\n" options:NSBackwardsSearch];

        if (breakRange.location == NSNotFound)
            breakRange = NSMakeRange(0, 1);

        if (range.location == NSNotFound) {
            range = NSMakeRange(0, 1);
        }

        if (range.location > breakRange.location)
        {
            textView.text = [textView.text stringByReplacingCharactersInRange:NSMakeRange(range.location, 1) withString:@"\n"];
        }
        else
        {
            textView.text = [textView.text stringByAppendingString:@"\n"];
        }
    }

    if ([text isEqualToString:@"\n"])
    {
        if ([lines count] == MAX_LENGTH_ROWS)
            return NO;
        else {
            return YES;
        }
        NSRange range = NSMakeRange(textView.text.length - 1, 1);
        [textView scrollRangeToVisible:range];
    }

    return YES;
}

与此同时,我已经有一段时间了,现在我失去了它。任何人都可以提供一些指针来将 UITextView 限制为我想要的 20 行/30 个字符的限制?

4

2 回答 2

0

这可能与您的总体目标背道而驰,但我脑海中最简单的答案是每次用户添加字符时都重新解析字符串。那么在哪里添加角色就无关紧要了。而不是在 shouldChangeTextInRange: 中执行所有这些操作:在 textViewDidChange: 中执行。你需要成为一个 UITextViewDelegate 并且你需要一个 NSString 类来保存最后一次成功的用户文本更新,以防你的用户尝试添加超出允许限制的字符。

像这样的东西:

-(void)textViewDidChange:(UITextView *)textView
{
    //Get the textview without any new line characters
    NSMutableString *temporaryString = [NSMutableString stringWithString:[textView.text stringByReplacingOccurrencesOfString:@"\n" withString:@" "]];
    bool updatePossible = true;

    int i = 0, numberOfLinesSoFar = 0;
    while(i + 30 < [temporaryString length])
    {
        //Go 30 characters in and start the reverse search for a word separation
        i += 30;
        int j = i;
        //Get the location of the final word separation in the current line
        while(j >= i && [temporaryString characterAtIndex:j] != ' ')
        {
            j--;
        }

        //This means we found a word separation
        if(j > i)
        {
            i = j;
            [temporaryString replaceCharactersInRange:NSMakeRange(i,1) withString:@"\n"];
        }
        //We didn't find a word separation
        else
        {
            //Here we will just have to break the line at 30.
            [temporaryString insertString:@"\n" atIndex:i];
        }

        numberOfLinesSoFar++;

        //Check if we just wrote line 20 and still have characters to go.
        if(numberOfLinesSoFar > 19 && i < [temporaryString length])
        {
            //Revert user change to the last successful character addition
            textView.text = lastSuccessfulViewString;
            updatePossible = false;
            break;
        }
    }

    if(updatePossible)
    {
        //If we are within the limits then update the global string (for undoing character additions) and the textview
        textView.text = temporaryString;
        lastSuccessfulViewString = temporaryString;
    }
}

现在这将不允许用户输入他们自己的换行符,但这可以用几个 if then 语句来处理。

于 2013-01-16T15:27:02.003 回答
0

经过一番摆弄,创建了一个包含 UITextView 作为子视图的控件。

我让这个控件处理文本换行并将委托方法转发到注册为委托的视图。

它可能对其他人有所帮助,因此我在此处发布了指向 BitBucket 的链接。

PS。它仍然非常冗长,但这是为了展示我如何为我的案例解决这个问题。

https://bitbucket.org/depl0y/sbframework/src/master/SBFramework/Views/SBTextView?at=master

于 2013-01-24T06:11:05.760 回答