UITextView自动换行,包含最大行长和行

时间:2013-01-16 14:30:03

标签: ios objective-c cocoa-touch

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

对于textview,有2个限制:

  1. 行数不得超过30个字符
  2. UITextView中只能有20行文本。
  3. 简而言之,最多是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个字符限制?

2 个答案:

答案 0 :(得分: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;
    }
}

现在这不允许用户输入他们自己的新行字符,但是如果那么语句可以用一对来处理。

答案 1 :(得分:0)

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

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

它可能对其他人有帮助,所以我在这里发布了一个指向BitBucket的链接。

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

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